Threejs / glTF - Black spots on mesh - three.js

I'm getting some weird black spots on a mesh loaded in threejs in glTF.
Anyone already have this problems before ?
The mesh is heavy 145 663 vertices, the biggest part have 89 000 vertices
I'm using version r94 of threejs and i load mesh with ths following code :
`
function setup(scene, camera, renderer) {
var loader = new THREE.GLTFLoader();
THREE.DRACOLoader.setDecoderPath( 'js/libs/draco/gltf/' );
loader.setDRACOLoader( new THREE.DRACOLoader() );
// Load a glTF resource
loader.load(
// resource URL
'mesh/ExportAllcleanNoMap.glb',
// called when the resource is loaded
function ( gltf ) {
gltf.scene.scale.set(10,10,10);
scene.add( gltf.scene );
var anim = gltf.animations[0];
mixer = new THREE.AnimationMixer( gltf.scene );
var action = mixer.clipAction(anim);
action.play();
orbitControls = new THREE.OrbitControls( camera, renderer.domElement );
orbitControls.target.set( 0, 1, 0 );
orbitControls.update();
light = new THREE.HemisphereLight( 0xbbbbff, 0x444422, 2 );
light.position.set( 0, 1, 0 );
scene.add( light );
scene.add(light);
var ambient = new THREE.AmbientLight( 0x222222 );
scene.add( ambient );
},
// called while loading is progressing
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
// called when loading has errors
function ( error ) {
console.log(error);
console.log( 'An error happened' );
}
);
}
`
Thanks.
Edit : Black spot not appear when draco compression is disabled. Looks like an issue between threejs, draco and heavy mesh.
Black spot on mesh

This looks like doubled up geometry. You somehow have two copies of the model perfectly on top of each other.
Check in your modelling software by selecting the vertices of one object and moving them and see if there is a duplicate hiding behind them.
If you are using blender, you can select a single vertex in the affected area in edit mode, and do ctrl L to select linked vertices... then move those aside and see if there is geometry hiding behind them.

Related

Not able to see the roughness on the non-metallic parts of the model, it looks correct in don mccurdy gltf viewer. What am I missing?

I have a model with some parts of it being metallic and others non-metallic. I have applied the environment map to get the correct reflections from the metallic parts of the model but the non metallic parts look equally reflective.
What should I do to make the non-metallic parts to appear less reflective and more rough as they are created. The model looks perfect in the Don Muccurdy’s gltf-viewer.
Please tell me what parameters do I need to change to get it right?
First is my rendered model and Second is the gltf viewer rendered model.
var rgbeLoader=new THREE.RGBELoader().setType( THREE.UnsignedByteType )
.setPath( 'textures/equirectangular/' )
.load( 'pedestrian_overpass_2k.hdr', function ( texture ) {
cubeGenerator = new THREE.EquirectangularToCubeGenerator( texture, { resolution: 1024 } );
cubeGenerator.update( renderer );
pmremGenerator = new THREE.PMREMGenerator( cubeGenerator.renderTarget.texture );
pmremGenerator.update( renderer );
pmremCubeUVPacker = new THREE.PMREMCubeUVPacker( pmremGenerator.cubeLods );
pmremCubeUVPacker.update( renderer );
envMap = pmremCubeUVPacker.CubeUVRenderTarget.texture;
var loader = new THREE.GLTFLoader();
loader.load( 'tfsProject4.glb', function ( gltf ) {
scene.add(gltf.scene);
gltf.scene.traverse((e)=>{
e.material.envMap=envMap;
});
});
The following code is called from a function after loading all the assets including the model shown.
const scene = new THREE.Scene();
modalCamera = new THREE.PerspectiveCamera( 75, modalCanHolder.width() /
modalCanHolder.height(), 0.001, 100 );
var light = new THREE.HemisphereLight( 0xffffbb, 0x080820, 1 );
scene.add( light );
var light = new THREE.AmbientLight( 0x808080 );
scene.add( light );
var directionalLight = new THREE.DirectionalLight( 0xffffff, .3 );
directionalLight.position.set(0,10,10)
scene.add( directionalLight );
modalRenderer = new THREE.WebGLRenderer({antialias: true, alpha:true});
modalRenderer.gammaOutput = true;
modalRenderer.gammaFactor = 2.2;
modalRenderer.physicallyCorrectLights=true;
modalRenderer.outputEncoding = THREE.sRGBEncoding;
modalRenderer.physicallyCorrectLights = true;
modalRenderer.setSize( modalCanHolder.width(), modalCanHolder.height() );
modalRenderer.setPixelRatio( window.devicePixelRatio );
modalCanHolder.append( modalRenderer.domElement );
modalRenderer.domElement.id = 'modalCanvas';
cubeGenerator.update( modalRenderer );
pmremGenerator.update( modalRenderer );
pmremCubeUVPacker.update( modalRenderer );
var controls = new THREE.OrbitControls( modalCamera, modalRenderer.domElement );
var prod=products[id];
scene.add(prod);
controls.update();
const animate = function () {
subAnimation=requestAnimationFrame( animate );
controls.update();
modalRenderer.render( scene, modalCamera );
};
animate();
Please help me get the rendering right.

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.

How can i store decals in Three.js and load them?

I have a model that when i click on the faces - it's adds decals (points or marks on the face) , i wonder how can i store the selection and load it later on.
I've followed the example Here and this is then function that stores the decal in array
function shoot() {
position.copy( intersection.point );
orientation.copy( mouseHelper.rotation );
if ( params.rotate ) orientation.z = Math.random() * 2 * Math.PI;
var scale = params.minScale + Math.random() * ( params.maxScale - params.minScale );
size.set( scale, scale, scale );
var material = decalMaterial.clone();
material.color.setHex( 0xffffff );
var m = new THREE.Mesh( new DecalGeometry( mesh, position, orientation, size ), material );
decals.push( m );
scene.add( m );
}
So i've tried to store the decals array and when the scene is loading - add them to the scene
scene.add( decals ); // just an idea
I also run in to this example - but still - i couldn't figure out how to do so.
Since decals are just meshes, you can serialize them with Object3D.toJSON() and restore them via ObjectLoader. I've update your fiddle to demonstrate this approach. The relevant code is:
const jsonString = JSON.stringify( scene.toJSON() );
scene = new THREE.ObjectLoader().parse( JSON.parse( jsonString ) );
When the scene object is restored, the decals should still be there. The only thing that disappears is the axes helper (since helpers can't be serialized/deserialized yet).

How do I export a gltf that works with Andorid scene-viewer?

I'm trying to use three.js to convert existing stls to gltf for use with the Android scene viewer (model-viewer component). However, the gltf I export fails to work with https://arvr.google.com/scene-viewer-preview with the error message "The glTF contains a vertex color, which is not supported by the Scene Viewer specification." It also fails when I load on an android phone using the model-viewer component, when I hit the AR button.
If I export a simple cube BoxBufferGeometry as gltf, that works in scene-viewer. However if I export a BoxGeometry (not Buffered) that also gives the vertex color error.
How do I tell three.js to not include vertex colors in the exported gltf?
The below code is what I'm using - the exportGLTF function is copied from the three.js examples. The stl file is just somthing simple I created from fusion 360.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var loader = new THREE.STLLoader();
loader.load( 'table.stl', function ( geometry ) {
var material = new THREE.MeshStandardMaterial();
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
exportGLTF(mesh);
}, undefined, function ( error ) {
console.error( error );
} );
var geometry = new THREE.BoxBufferGeometry( 1, 1, 1 );
var material = new THREE.MeshStandardMaterial();
cube = new THREE.Mesh( geometry, material );
cube.position.set( 0, 0, 0 );
cube.name = "Cube";
scene.add( cube );
exportGLTF(cube);
If you don't care about the vertex colors, you can just delete that attribute from the BufferGeometry that STLLoader produces. I found that Scene Viewer also doesn't like that the geometry is non-indexed. You can work around that with the mergeVertices function in BufferGeometryUtils.
Here's a working example: https://glitch.com/edit/#!/chartreuse-steed
var loader = new THREE.STLLoader();
loader.load(
stlUrl,
function(geometry) {
// Delete vertex colors, since Scene Viewer doesn't support them.
geometry.deleteAttribute("color");
// Apparently Scene Viewer also doesn't support non-indexed geometry,
// so we do this mergeVertices operation just to get an indexed geometry
geometry = THREE.BufferGeometryUtils.mergeVertices(geometry);
var material = new THREE.MeshStandardMaterial();
material.vertexColors = THREE.VertexColors;
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
exportGLTF(mesh);
},
undefined,
function(error) {
console.error(error);
}
);

Regarding Threejs texture Animation

I'm Working with Threejs in which I'm Facing Problems with Textures, so I would like to ask A question that is, how to load the textures without starting the animation, it shows blank image without starting the animation. Can anyone tell me how to do that..
var geometry = new THREE.PlaneGeometry( 15, 5.3, 2 );
var te = new THREE.ImageUtils.loadTexture("b4.jpg") ;
var material = new THREE.MeshBasicMaterial( {color: "",map:te} );
plane = new THREE.Mesh( geometry, material);
plane.position.set(-12.89,-7.2,19);
plane.visible=false;
scene.add( plane );
Did you try having a callback function to trigger after the texture is successfully loaded? Like how it is done in the documentation: TextureLoader
So something like:
var geometry = new THREE.PlaneGeometry( 15, 5.3, 2 );
var loader = new THREE.TextureLoader();
// load a resource
loader.load(
// resource URL
'b4.jpg',
// Function when resource is loaded
function ( texture ) {
// do something with the texture
var material = new THREE.MeshBasicMaterial( {color: "",map:te} );
plane = new THREE.Mesh( geometry, material);
plane.position.set(-12.89,-7.2,19);
plane.visible=false;
scene.add( plane );
},
// Function called when download errors
function ( xhr ) {
console.log( 'An error happened' );
}
);

Resources