GLTF Animation doesn't play when adding in material Three.js - three.js

I have a working GLTF animation that automatically starts playing when the page loads, however whenever I try to add a material to it, the animation no longer plays but the material appears. How do I fix this or if there is an easier way just to add a block colour to a gltf model please let me know, thanks.
var loader = new THREE.GLTFLoader();
loader.setDRACOLoader( new THREE.DRACOLoader() );
// Load a glTF resource
loader.load(
// resource URL
'../models/fox3.gltf',
// called when the resource is loaded
function ( gltf ) {
gltf.animations; // Array<THREE.AnimationClip>
gltf.scene; // THREE.Scene
gltf.scenes; // Array<THREE.Scene>
gltf.cameras; // Array<THREE.Camera>
gltf.asset; // Object
//Loading in and positioning model
var object = gltf.scene;
object.scale.set(10,10,10);
object.position.set (-300, 20,-400);
object.rotation.y = 0.5;
//Playing Animation
mixer = new THREE.AnimationMixer(gltf.scene);
console.log(gltf.animations)
mixer.clipAction( gltf.animations[0] ).play();
//Adding texture/colour to model (causes animation to stop playing)
// materialObj = new THREE.MeshBasicMaterial( { color: "#9E4300"} );
// object.traverse(function(child){
// if (child instanceof THREE.Mesh){
// //child.material = materialObj;
// }
// });
console.log(object);
scene.add( object )
});

or if there is an easier way just to add a block colour to a gltf model please let me know, thanks.
I'll address this last part of your question. The MeshBasicMaterial has the lighting calculations turned off, and in glTF this is supported with an extension called KHR_materials_unlit.
Here's a sample model called BoxUnlit.gltf that shows this extension in action. Two key places to note are ExtensionsUsed at the top, and the material near the bottom.
One major gotcha here is that the material's BaseColorFactor is specified in linear colorspace, while textures are provided in sRGB colorspace. So you have to take your chosen color and convert it to linear, typically by mathematically raising each component to the power of 2.2.
For example, your question contains color value #9E4300, which in 0..255 scale is equal to (158, 67, 0). Divide each number by 255, then raise by 2.2:
Red == (158 / 255.0) ** 2.2 == 0.348864834
Green == ( 67 / 255.0) ** 2.2 == 0.052841625
Blue == ( 0 / 255.0) ** 2.2 == 0.0
Use those values as the RGB values of the glTF model's BaseColorFactor, along with an alpha value of 1.0, like so:
"materials": [
{
"pbrMetallicRoughness": {
"baseColorFactor": [
0.348864834,
0.052841625,
0.0,
1.0
]
},
"extensions": {
"KHR_materials_unlit": {}
}
}
],
With that, ThreeJS should automatically select the MeshBasicMaterial for the model.

Try changing the skinning to true on the material of gltb and it should work. I had the same problem earlier.

Related

Ready Player Me Avatar texture/lightning rendering in ThreeJS and Matterport

I try to import a Ready Player Me GLB avatar into a Matterport scene (in ThreeJS).
It works but the avatar is very flat (left picture) compared to the rendering into RPM (right picture) or basic GLTF Viewer. I don't understand what I missed ? Pseudo code :
const gltfLoader = new THREE.GLTFLoader();
gltfLoader.load('https://api.readyplayer.me/v1/avatars/63580183b445da7aa57b9ce3.glb',
(gltf) => {
this.mesh = gltf.scene;
const light = new THREE.AmbientLight( 0xFFFFFF, 1 );
light.castShadow = true
this.mesh.add( light );
...
}, undefined);
On the WebGL part I have access to Matterport renderer :
(renderer, THREE, effectComposer) => {
renderer.outputEncoding = THREE.sRGBEncoding
renderer.toneMapping = THREE.ACESFilmicToneMapping
}
Is it related to Antialias ? Or a paramter or lighting that flatten hair and hands ? Or is it related to texture ?
Thanks !
EDIT 11/12/2022:
Thanks to #Mugen87, I find how to use the EquirectangularShader from GLTFLoader sample. This code works with Matterport context.
let pmremGenerator = new THREE.PMREMGenerator( this.context.renderer );
pmremGenerator.compileEquirectangularShader();
let envMap = pmremGenerator.fromScene( new THREE.RoomEnvironment() ).texture;
this.context.scene.environment = envMap;
Instead of using a single instance of AmbientLight, apply a more advanced type of environmental lighting to your scene. Especially if you already enabled tone mapping, consider to use a HDR environment map. The basic GLTFLoader example of three.js is a good code template. The most important part is:
new RGBELoader()
.load( 'textures/equirectangular/royal_esplanade_1k.hdr', function ( texture ) {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = texture;
// more scene setup
} );
Applying an environment map to Scene.environment ensures all PBR materials in the scene are going to use it.

glb mesh disappears on rotation threejs

I've dug around looking for a solve for this - but couldn't find the answer on here. I have a gltf/glb model loading into three js as such:
createScene: function() {
this.renderer = new Three.WebGLRenderer({
antialias: true,
alpha: true
});
let container = document.getElementById('container');
this.renderer.setSize(container.clientWidth, container.clientHeight);
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setClearColor(new Three.Color('#fff'));
this.renderer.setClearAlpha( 0 );
//this.render.shadowMap.type = Three.PCFSoftShadowMap;
container.appendChild(this.renderer.domElement);
},
createCamera: function() {
this.camera = new Three.PerspectiveCamera(6, container.clientWidth/container.clientHeight, 1, 1000);
this.camera.position.set(0, 0, 40);
},
createShape: function() {
let me = this;
const loader = new GLTFLoader();
loader.load( 'model/fbf3.glb', function ( gltf ) {
me.bottle = gltf.scene
me.scene.add( gltf.scene );
gltf.scene.traverse(function(obj) { obj.frustumCulled = false; });
me.pivot = new Three.Group();
me.pivot.position.set( 0.0, 0.0, 0 );
me.bottle.add( me.pivot );
console.log(gltf.scene);
console.log(gltf.scene.children[1]);
//me.pivot.add( me.bottle );
me.animate();
}, undefined, function ( error ) {
console.error( error );
});
},
I found a post that said to loop through the scene and be sure to add frustumCulled to false - so that's added in ( and when I log the child, that objects frustumCulled is set to false ). In order to have a label on my object easy to map and also take on a different material/glossiness i've created another object in the group that is just slightly in front of my other object on the yaxis. When it is facing the camera, it works well - however, it is when the object rotates is where it disappears. Working:
Rotate enough, and gone:
Is there a setting in threejs that I need to add to be sure the render order is correct? Or is it something wrong with my object set up in Blender? Ideally I wouldn't have to UV wrap the whole bottle as one object and add the label to the bottle texture because I want the label to have less specularity ( that a word? ). Any help would be appreciated.
Solved - the tutorial is slightly old ( 2+years ) and now Blender ( the latest version 2.9+ ) has the Principled BSDF Shader baked in. Instead of using the glTF-Blender-Exporter-Master pbr appended shaders from the listed tutorial - I instead used the Principled BSDF Shader - linked my material to it's Base Color and linked that to the Material Output ( all in the node/now Shader Editor. No issues anymore.

Three.js : Gltf object adding material to look better

I'm actually trying to add some materials to my Gltf objects in three js r113, but I don't know how to use correctly material parameters and the light as I see my object in three js viewer. This is What I get in Firefox
and this is what I'm dreaming about
.
I guess this is the value I need to apply to my code
This is how I add my gltf and how I try to add materials :
// Load a glTF resource of FENCE
gltfLoader.load( 'Fence.gltf', function ( gltf ) {
fenceModel = gltf.scene;
// fenceModel.traverse(function (child) {
// if (child.isMesh) {
// child.material = new THREE.MeshLambertMaterial({
// color: 0xc07341, //light Brown
// reflectivity: 0,
// dithering: true
// });
// }
// });
});
var ambientlight = new THREE.AmbientLight(0xffffff, 0.5 );
scene.add( ambientlight );
Actually my floor is only a gltf file with no materials.
Maybe I need to add some shadow porperties to my floor and then I could see the fence shadow ?
I need some help to understand how to do a better light effect on object.
Thank you, sorry for my english I'm using translator to help me.
Ps: My gltf object contain texture in it.

Three.js: Add a texture to an object just on the outside

I'm very new with Three.js and I'm trying to make a ring:
http://www.websuvius.it/atma/myring/preview.html
I have a background texture ( the silver one ) and another one with a text.
I want the text only on the ring external face.
This is part of my code:
var loader = new THREE.OBJLoader( manager );
var textureLoader = new THREE.TextureLoader( manager );
loader.load( 'assets/3d/ring.obj', function ( event ) {
var object = event;
var geometry = object.children[ 0 ].geometry;
var materials = [];
var backgroundTexture = textureLoader.load('img/texture/silver.jpg');
backgroundTexture.flipY = false;
var background = new THREE.MeshBasicMaterial({
map: backgroundTexture,
color: 0xffffff
});
materials.push(background);
var customTexture = textureLoader.load('img/text.png');
customTexture.flipY = false;
var custom = new THREE.MeshBasicMaterial({
map: customTexture,
transparent: true,
opacity: 1,
color: 0xffffff
});
materials.push(custom);
mesh = THREE.SceneUtils.createMultiMaterialObject(geometry, materials);
mesh.position.y=-50;
scene.add(mesh);
}, onProgress, onError );
It is possible?
Thanks
The reason behind your issue appears to be in your .obj file. Judging from a quick glance at the texture coordinates stored in the file, the inside of the ring uses the same part of the texture image as the outside of the ring.
Increasing the transparent parts of the image won't help. Neither will the attempts to stop the texture from repeating. Those would help if the texture coordinates were larger than 1 but this is not your case unfortunately.
However, there are several solutions:
Split the object in a 3D modeling software to two objects - outside and inside of the ring - and apply the texture only to the first one.
Adjust the UV coordinates of the object in a 3D modeling software.
Adjust the UV coordinates of the vertices programmatically after loading the object to Three.JS

Threejs Raycasting a Sprite-Canvas Object is inaccurate [duplicate]

I am trying to use THREE.Raycaster to show an html label when the user hover an object. It works fine if I use THREE.Mesh but with THREE.Sprite it looks like that there is a space that increases with the scale of the object.
The creation process is the same for both scenario, I only change the type based on USE_SPRITE variable.
if ( USE_SPRITE ) {
// using SpriteMaterial / Sprite
m = new THREE.SpriteMaterial( { color: 0xff0000 } );
o = new THREE.Sprite( m );
} else {
// using MeshBasicMaterial / Material
m = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
o = new THREE.Mesh(new THREE.PlaneGeometry( 1, 1, 1 ), m );
}
https://plnkr.co/edit/J0HHFMpDB5INYLSCTWHG?p=preview
I am not sure if it is a bug with THREE.Sprite or if I am doing something wrong.
Thanks in advance.
three.js r73
I would consider this a bug in three.js r.75.
Raycasting with meshes in three.js is exact. However, with sprites, it is an approximation.
Sprites always face the camera, can have different x-scale and y-scale applied (be non-square), and can be rotated (sprite.material.rotation = Math.random()).
In THREE.Sprite.prototype.raycast(), make this change:
var guessSizeSq = this.scale.x * this.scale.y / 4;
That should work much better for square sprites. The corners of the sprite will be missed, as the sprite is treated as a disk.
three.js r.75

Resources