I have a model with a bump map. It displays great in the three.js editor, but when I export the scene and load it into a scene, the model displays without the bump map. It's puzzling because the envMap and specularMap are loading just fine, but no bump map. Any ideas?
The exported json is here: https://www.dropbox.com/sh/xj8plnceoce1gwh/AABWChVTw6TW2hPXr5a3t9Tpa/Backpack_3_scene.json?dl=0
Here is my code for loading the exported json:
// scene
scene = new THREE.Scene();
// model
var onProgress = function ( xhr ) {
if ( xhr.lengthComputable ) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log( Math.round(percentComplete, 2) + '% downloaded' );
}
};
var onError = function ( xhr ) {
};
var loader = new THREE.ObjectLoader();
loader.load(model_json, function(json_scene) {
scene.add(json_scene);
render();
}, onProgress, onError);
In your json model file the bumpScale is set to 0.04. THat is very small to have any effect. You probably need to scale it up.
Related
I'm trying to use the THREE.JS InstancedMesh to make copies of an imported gltf file, but nothing shows up in the scene. This is the code I've used so far:
const equatorMaterial = new THREE.MeshStandardMaterial({color: 0x242526, metalness:1,
opacity:0.8, roughness:0.8} )
let ball;
const loader = new GLTFLoader()
loader.load( './ball.gltf', function ( gltf ) { //load sphere
gltf.scene.traverse(function(model) {
if (model.isMesh) {
//model.castShadow = true;
ball = model.geometry
}
});
let mesh = new THREE.InstancedMesh(ball, equatorMaterial, 20)
scene.add( mesh )
}, undefined, function ( error ) {
console.error( error );
} );
Trying to load this model of a car into my scene, here is how it looks in the glTF Viewer:
I followed that example. With this updated loading method, the model is still dark, and if I try to scale or position it, it completely disappears.
Here is how it's loaded:
const loader = new THREE.GLTFLoader();
const roughnessMipmapper = new RoughnessMipmapper( renderer );
loader.load( 'models/car_datsun/scene.gltf', function ( gltf ) {
gltf.scene.traverse( function (child) {
if (child.isMesh) {
roughnessMipmapper.generateMipmaps(child.material);
}
child.scale.set(0.5,0.5,0.5); //must comment this line out to appear
child.position.y += 10; //must comment this line out to appear
child.position.z += 20; //must comment this line out to appear
});
scene.add(gltf.scene);
}, undefined, function ( error ) {
console.error(error);
});
roughnessMipmapper.dispose();
I also have a light, which is meant to simulate the sun:
const light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.set(500,200,500); //looking at 0,0,0
scene.add(light);
Renderer is set to use sRGB:
renderer.outputEncoding = THREE.sRGBEncoding;
I've got a textured model in three.js and I want to be able to swap out the texture defined in the .gltf file when the page loads. I've looked here for inspiration.
"images": [
{
"uri": "flat_baseColor.png"
},
// etc
So to update the texture I do
var images = [
"./textures/01.jpg",
// "./textures/01.jpg",
];
var texture = new THREE.TextureLoader().load( images[0] );
var my_material = new THREE.MeshBasicMaterial({map: texture});
// load the model
var loader = new GLTFLoader().setPath( 'models/gltf/' ); // trex
loader.load( 'creature_posed.gltf', function ( gltf )
{
gltf.scene.traverse( function ( child )
{
if ( child.isMesh )
{
// The textures go for a double flip, I have no idea why
// Texture compensation
texture.flipX = false;
texture.flipY = false;
child.material = my_material;
texture.needsUpdate = true;
}
} );
var model = gltf.scene;
Only the texture is considerably pale. :(
I've tested it against itself, so it's not the texture). What have a missed out?
When loading textures you'll need to pay attention to colorspace: if the texture has color data (like .map or .emissiveMap) it's probably sRGB.
texture.encoding = THREE.sRGBEncoding;
See GLTFLoader docs and color management in three.js. This assumes that renderer.outputEncoding = THREE.sRGBEncoding as well.
three.js r113
I originally had an animate function in place for my three.js scene that is loaded within an AngularJS Modal, but found that after closing the Modal, the animation keeps going, and that is unneeded since I don't require constant animation like a video game would have.
At this point, I switched it to only render when someone uses the OrbitControls to move the simple box in my example, and have an initial call to render the scene so that users can see the box instead of a big blacked out square.
However, upon initial render, the texture does not appear to be applied until I use the orbit controls and move the box, at which point they appear. This is odd, since both my initial call and the listener tied to the OrbitControls are to the same function. How do I get the initial load to show the texture?
$scope.generate3D = function () {
// 3D OBJECT - Variables
var texture0 = baseBlobURL + 'Texture_0.png';
var boxDAE = baseBlobURL + 'Box.dae';
var scene;
var camera;
var renderer;
var box;
var controls;
var newtexture;
// Update texture
newtexture = THREE.ImageUtils.loadTexture(texture0);
//Instantiate a Collada loader
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load(boxDAE, function (collada) {
box = collada.scene;
box.traverse(function (child) {
if (child instanceof THREE.SkinnedMesh) {
var animation = new THREE.Animation(child, child.geometry.animation);
animation.play();
}
});
box.scale.x = box.scale.y = box.scale.z = .2;
box.updateMatrix();
init();
// Initial call to render scene, from this point, Orbit Controls render the scene per the event listener
render();
});
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xdddddd);
//renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setSize(500, 500);
// Load the box file
scene.add(box);
// Lighting
var light = new THREE.AmbientLight();
scene.add(light);
// Camera
camera.position.x = 40;
camera.position.y = 40;
camera.position.z = 40;
camera.lookAt(scene.position);
// Rotation Controls
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.addEventListener('change', render);
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 5;
controls.noZoom = false;
controls.noPan = false;
var myEl = angular.element(document.querySelector('#webGL-container'));
myEl.append(renderer.domElement);
}
function render() {
renderer.render(scene, camera);
console.log('loaded');
}
}
You are using ColladaLoader and you want to force a call to render() when the model and all the textures are loaded.
If you add the model to the scene in the loader callback, there is still a chance that even though the model has loaded, the textures may not have.
One thing you can do is add the following before instantiating the loader:
THREE.DefaultLoadingManager.onLoad = function () {
// console.log( 'everything loaded' ); // debug
render();
};
Or alternatively,
THREE.DefaultLoadingManager.onProgress = function ( item, loaded, total ) {
// console.log( item, loaded, total ); // debug
if ( loaded === total ) render();
};
three.js r.72
Since the Three.js migration (r68 -> r69) the ColladaLoader returns a Scene instead of an Object3D. How can I get the loaded Object3D now? I want store the loaded Object in a var to use it everytime.
var newpos = Cube.position;
var oLoader = new THREE.ColladaLoader();
oLoader.load('models/logo.dae',
function(collada)
{
var object = collada.scene;
var skin = collada.skins[0];
object.rotation.x = -Math.PI / 2;
object.rotation.z = Math.PI / 2;
object.position.x = newpos.x;
object.position.y = newpos.y+1.85;
object.position.z = newpos.z;
object.scale.set(0.75, 0.75, 0.75);
object.updateMatrix();
scene.add(object);
},
function ( xhr ) {
// console.log( (xhr.loaded / xhr.total * 100) + '% loaded' );
}
);
The ColladaLoader returns a scene because the loaded Model is'nt created as a 3DObject. The ColladaLoader creates a new scene added to your scene including the loaded .dae-Model. (Now it returns a group) That's because not every Model is just one Object. Check the childs of the dae.scene that you loaded, it helps a lot.