GLTF model is too dark - three.js

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;

Related

How do I get the THREE.JS InstancedMesh working?

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 );
} );

Updated textures stops animation in three.js

Moving on from yesterday. I'm swapping out a texture on a .GLTF on page refresh. The texture now works fine and dandy...
But only on files that have no animation. The texture update however, seems to stop them in their literal tracks. I've not sure what's causing it or how to reload the animations.
Here's the code:
var creaturePath = "models/gltf/creature/";
var creatureFile = "creature_roar.gltf";
// load the model
var loader = new GLTFLoader().setPath( creaturePath ); // creature
loader.load( creatureFile, function ( gltf )
{
gltf.scene.traverse( function ( child )
{
if ( child.isMesh )
{
// override textures
texture.flipX = false;
texture.flipY = false;
my_material = new THREE.MeshBasicMaterial({map: texture});
// child.material = my_material; // this is the problem line
texture.needsUpdate = true;
}
} );
var model = gltf.scene;
If you replace the material, you have to ensure to set MeshBasicMaterial.skinning and/or MeshBasicMaterial.morphTargets to true. Otherwise skeletal and/or morph target animation won't be supported by the material.
three.js R113

Update texture with three.js

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

Initial render of threejs scene doesn't add texture

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

Need to render textures uploaded by user in input files with Canvas renderer three.js

I've loaded a Blender model using the three.js library and want to allow the users to change the texture of some faces through an input field in a form. I don't have any problem when I use the WebGLRenderer, and it works fine in Chrome, but it doesn't work with the canvas renderer when the texture coming from the input is in data:image... format. Seems if I load a full path image from the server it works fine. Does anybody know if there's a way to load textures this way and render them with the canvasrenderer?
Thank you.
I add here the code after I set the camera, lights and detect it the browswer detects webgl or not to use the WebGLRenderer or the CanvasRenderer.
First I load the model from blender:
var loader = new THREE.JSONLoader();
loader.load('assets/models/mimaquina9.js', function (geometry, mat) {
//I set the overdraw property to 1 for each material like i show here for 16
mat[16].overdraw = 1;
mesh = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(mat) );
mesh.scale.x = 5;
mesh.scale.y = 5;
mesh.scale.z = 5;
scene.add(mesh);
}, 'assets/images');
render();
//To render, I try to make an animation in case WebGL is available and just render one frame in case of using the canvas renderer.
function render() {
if(webgl){
if (mesh) {
mesh.rotation.y += 0.02;
}
// render using requestAnimationFrame
requestAnimationFrame(render);
webGLRenderer.render(scene, camera);
}
else if(canvas){
camera.position.x = 30;
camera.position.y = 20;
camera.position.z = 40;
camera.lookAt(new THREE.Vector3(0, 10, 0));
setTimeout(function (){
//something you want delayed
webGLRenderer.render(scene, camera);
}, 1000);
}
}
$('#datafile').change(function(e)
{
e.preventDefault();
var f = e.target.files[0];
if(f && window.FileReader)
{
var reader = new FileReader();
reader.onload = function(evt) {
console.log(evt);
mesh.material.materials[16].map = THREE.ImageUtils.loadTexture(evt.target.result);
if(canvas && !webgl){
//I read that might be a problem of using Lambert materials, so I tried this commented line without success
//mesh.material.materials[16] = new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture(evt.target.result)});
//If I uncomment the next line, it displays the texture fine when rendering after.
//mesh.material.materials[16].map = THREE.ImageUtils.loadTexture("assets/images/foto.jpg");
render();
}
}
reader.readAsDataURL(f);
}
});
Thanks once more.
evt.target.result is a DataURL so you should assign that to a image.src. Something like this should work:
var image = document.createElement( 'img' );
image.src = evt.target.result;
mesh.material.materials[16].map = new THREE.Texture( image );

Resources