Three.JS gltf model disappearing when using left click orbit control - javascript

Well, the title pretty much says it all.
I am using camera-controls for OrbitControls (because the official one doesn't seem to work anymore), and recently popped into that problem :
Whenever I press left click and drag my mouse, the model simply disappears and can never be found again. Zooming works perfectly and can't seem to find any potential solution for that matter.
Hope you can help! Here is the code. Thank you in advance!
import cameraControls from 'https://cdn.skypack.dev/camera-controls';
import { GLTFLoader } from 'https://cdn.skypack.dev/three#0.129.0/examples/jsm/loaders/GLTFLoader.js';
cameraControls.install( { THREE: THREE } )
let obj, controls;
const scene = new THREE.Scene();
const camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 0.01, 1000 );
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
camera.position.z = 50;
const loader = new GLTFLoader();
loader.load("../models/EGLISE.glb", function(gltf) {
obj = gltf.scene
scene.add(obj);
gltf.animations;
}, undefined, function(error){
console.error(error);
});
controls = new cameraControls( camera, renderer.domElement );
controls.minZoom = 1;
controls.maxZoom = 5;
const ambientlight = new THREE.AmbientLight( 0xffffff );
scene.add( ambientlight );
const light = new THREE.PointLight( 0xff0000, 1, 100 );
light.position.set( 50, 50, 50 );
scene.add( light );
const animate = function () {
if(obj){
obj.rotation.y += 0.001;
// document.addEventListener("mousedown", function() {
// obj.rotation.y += 0.01;
// })
controls.update();
}
requestAnimationFrame( animate );
renderer.render( scene, camera );
};
if ( WEBGL.isWebGLAvailable() ) {
animate();
} else {
const warning = WEBGL.getWebGLErrorMessage();
document.getElementById( 'container' ).appendChild( warning );
}

Related

ThreeJS - Trouble loading FBX file

I've got some fairly simple ThreeJS, just trying to add an FBX object into my scene. However, whenever I run it I get "uncaught TypeError: THREE.fbxloader is not a constructor" at line 15, which is where I call the FBXLoader. I've tried replacing both the FBXLoader.js and Three.js files with the latest builds, but nothing has worked.
Here's my code:
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.FBXLoader();
loader.load( 'thrown.fbx', function ( object ) {
mixer = new THREE.AnimationMixer( object );
var action = mixer.clipAction( object.animations[ 0 ] );
action.play();
object.traverse( function ( child ) {
if ( child.isMesh ) {
child.castShadow = true;
child.receiveShadow = true;
}
} );
scene.add( object );
} );
var gridHelper = new THREE.GridHelper( 50, 50 );
scene.add( gridHelper );
camera.position.z = 20;
camera.position.y = 10;
var animate = function () {
requestAnimationFrame( animate );
renderer.render( scene, camera );
};
animate();
Any help would be much appreciated! Have been working at this for hours to no avail.

threeJs wrong (too low) camera position

I am new to ThreeJS, what I am trying to accomplish is to load a gltf model, which is correctly shown in three-gltf-viewer, it is valid.
When I load it into threeJS, the model loads up ok but the camera is placed on the horizon line of the model, and the orbit control does not work when I try to zoom in and out or any other rotation of the scene is disabled.
I tried to tweak any possible values of camera and scene but I just can't "jump on top" of the model and see it from above. Here is the code.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 800, window.innerWidth / window.innerHeight, 500, 1500000 );
camera.position.set(1, 1, 1);
var renderer = new THREE.WebGLRenderer({ alpha: false });
renderer.setClearColor( 0xC5C5C3 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls( camera, renderer.domElement );
var ambientLight = new THREE.AmbientLight( 0xcccccc );
scene.add( ambientLight );
var directionalLight = new THREE.DirectionalLight( 0xffffff );
directionalLight.position.set( 0, 1, 1 ).normalize();
scene.add( directionalLight );
// Instantiate a loader
var loader = new THREE.GLTFLoader();
loader.load('GLTF_local_coord_sys/GEOTIFF_local_coord_sys.gltf',
function(gltf) {
var object = gltf.scene;
gltf.scene.scale.set( 0.65, 0.65, 0.65 );
gltf.scene.position.x = 1;
gltf.scene.position.y = 1;
gltf.scene.position.z = 1;
scene.add( gltf.scene );
camera.lookAt(scene.position);
},
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
function ( error ) {
console.log( 'An error happened' );
}
);
camera.position.z =25;
function animate() {
render();
requestAnimationFrame( animate );
}
function render() {
renderer.render( scene, camera );
}
render();
animate();
Does anyone know how to fix this?

After converting my FBX file to a .gltf, the model is incredibly small, why?

QUESTION:
After converting my FBX file to a .gltf, the model is incredibly small, why ?
I tried scaling the model with frontObject.scale.set( 1000, 1000, 1000 ); but I get the following error:
TypeError: Cannot read property 'set' of undefined
Furthermore, in
function ( xhr ) {
progressBar.style.display = "block";
progressBar.style.width = ( xhr.loaded / xhr.total * 100 ) + '%';
loadingText.innerHTML = 'Loading... '+xhr.loaded+"/"+xhr.total;
// For some reason, xhr.total = 0, so I can't use it
setTimeout(function () {
frontObject.scale.set( 1000, 1000, 1000 );
}, 3000);
},
xhr.total is always equal to 0 and xhr.loaded is equal to an absurdly large number.
All I did was convert my file from .fbx to .gltf and change the size of the textures from 2048x2048 to 1024x1024.
Here is a screenshot of what I am now seeing:
Before, the model would take the whole vertical height.
CODE:
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var container, stats, controls;
var camera, scene, renderer, light;
var clock = new THREE.Clock();
var frontObject;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.set( 100, 200, 300 );
camera.lookAt(new THREE.Vector3(0,0,0));
controls = new THREE.OrbitControls( camera );
controls.target.set( 0, 100, 0 );
controls.update();
scene = new THREE.Scene();
scene.background = new THREE.Color( 0xa0a0a0 );
scene.fog = new THREE.Fog( 0xa0a0a0, 200, 1000 );
light = new THREE.HemisphereLight( 0xffffff, 0x444444 );
light.position.set( 0, 200, 0 );
scene.add( light );
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 200, 100 );
light.castShadow = true;
light.shadow.camera.top = 180;
light.shadow.camera.bottom = -100;
light.shadow.camera.left = -120;
light.shadow.camera.right = 120;
scene.add( light );
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 0, -50 );
light.castShadow = true;
light.shadow.camera.top = 180;
light.shadow.camera.bottom = -100;
light.shadow.camera.left = -120;
light.shadow.camera.right = 120;
scene.add( light );
// scene.add( new THREE.CameraHelper( light.shadow.camera ) );
// ground
var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2000, 2000 ), new THREE.MeshPhongMaterial( { color: 0x999999, depthWrite: false } ) );
mesh.rotation.x = - Math.PI / 2;
mesh.receiveShadow = true;
scene.add( mesh );
var grid = new THREE.GridHelper( 2000, 20, 0x000000, 0x000000 );
grid.material.opacity = 0.2;
grid.material.transparent = true;
scene.add( grid );
load();
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.shadowMap.enabled = true;
container.appendChild( renderer.domElement );
renderer.setSize( window.innerWidth, window.innerHeight );
}
function load() {
// Instantiate a loader
var loader = new THREE.GLTFLoader();
// Optional: Provide a DRACOLoader instance to decode compressed mesh data
THREE.DRACOLoader.setDecoderPath( '../path/' );
THREE.DRACOLoader.setDecoderConfig( { type: 'js' } );
loader.setDRACOLoader( new THREE.DRACOLoader() );
// Load a glTF resource
loader.load(
// resource URL
'../path/file.gltf',
// called when the resource is loaded
function ( gltf ) {
scene.add( gltf.scene );
gltf.animations; // Array<THREE.AnimationClip>
gltf.scene; // THREE.Scene
gltf.scenes; // Array<THREE.Scene>
gltf.cameras; // Array<THREE.Camera>
gltf.asset; // Object
frontObject = gltf.asset;
},
// called while loading is progressing
function ( xhr ) {
progressBar.style.display = "block";
progressBar.style.width = ( xhr.loaded / xhr.total * 100 ) + '%';
loadingText.innerHTML = 'Loading... '+xhr.loaded+"/"+xhr.total;
// For some reason, xhr.total = 0, so I can't use it
setTimeout(function () {
frontObject.scale.set( 1000, 1000, 1000 );
}, 3000);
},
// called when loading has errors
function ( error ) {
console.log( 'An error happened: '+error );
}
);
}
function animate() {
requestAnimationFrame( animate );
if ( mixers.length > 0 ) {
for ( var i = 0; i < mixers.length; i ++ ) {
mixers[ i ].update( clock.getDelta() );
}
}
renderer.render( scene, camera );
}
FIDDLE:
https://jsfiddle.net/Username100/y54kpe1h/64
I was able to load the model at the correct size ! But it seems that the default loading manager was incorrectly indicating that everything had loaded, how could that be ?
Sometimes in GLTF files the final size of the object is dictated by parent nodes that apply transforms.
In your code, i'm not sure that
gltf.asset; // Object
frontObject = gltf.asset;
is really your object.
The real object is a child of the gltf.scene and can be found using gltf.scene.traverse or .getObjectByName(
I fixed up your raycasting thing:
https://jsfiddle.net/manthrax/8evurmyx/44/

Three JS TextGeometry always facing user

This is my source code.
I'm trying to make the TextGeometry always look to the camera?It's possible?
Code:
var stats;
var camera, controls, scene, renderer;
init();
render();
function init() {
scene = new THREE.Scene();
var ambient = new THREE.AmbientLight( 0xFFFFFF );
scene.add( ambient );
var container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({antialias: 1 });
renderer.shadowMap.enabled = true;
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight);
renderer.setClearColor(0x013A65);
container.appendChild( renderer.domElement );
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 5000 );
camera.position.set(0,0,0);
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', render );
controls.enableKeys = false;
controls.enableZoom = true;
controls.minDistance = 2000;
controls.maxDistance = 3500;
controls.maxPolarAngle = Math.PI/2;
// world
var onError = function ( xhr ) { };
THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() );
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath( './assets/3d/' );
mtlLoader.load( 'A.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
mtlLoader.setPath( './assets/3d/' );
objLoader.load( './assets/3d/A.obj', function ( object ) {
object.position.x = 0;
object.position.y = 0;
object.position.z = 0;
scene.add( object );
}, onError );
});
//Text
var loader = new THREE.FontLoader();
loader.load( './fonts/Open_Sans_Regular.json', function ( font ) {
var textGeometry = new THREE.TextGeometry( "Test", {font: font, size: 22, height: 3, curveSegments: 1});var textMaterial = new THREE.MeshPhongMaterial({ color: 0xFFFFFF, specular: 0xFFFFFF });var mesh1 = new THREE.Mesh( textGeometry, textMaterial );mesh1.position.x = -200;mesh1.position.y = 250;mesh1.position.z = 725;scene.add( mesh1);});
// lights
light = new THREE.DirectionalLight( 0xFFFFFF );
light.position.set( 1, 1, 1 );
scene.add( light );
window.addEventListener( 'resize', onWindowResize, true );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
stats.update();
render();
}
function render() {
renderer.render( scene, camera );
}
I already tried mesh.lookAt(camera.position) inside the render function but no sucess.
Best Regards.
I believe your question is how to make the text appear regardless of where the camera is. Instead of using text geometry you can try to put your text in a div container and make the position absolute using CSS. https://threejs.org/docs/#manual/en/introduction/Creating-text

Stripped shadows on collada objects

I have a scene with two collada objects and a directional light.
The first collada is pretty much a plane, and the second one is made of multiple boxes.
It appears that when the scene is rendered, some "side" shadows are really stripped, although the shadows casted on ground are pretty well rendered.
.
As I was searching for an answer, I figured out it might be a problem with my collada, so I added a basic cube to the scene (the big one above all), but it seems it has the same problem.
Does anyone have a tip or know this problem already?
I'm using the last three.js revision atm (r71), tested on Google Chrome and Mozilla Firefox (MacOS).
I already tried to tweak pretty much all the shadow* attributes of the directional light, except the ones related with shadowCascade (which I don't use).
I also tested to tweak shadow-related renderer's attributes.
Here's my light setup:
var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 );
directionalLight.target.position = THREE.Vector3(0, 0, 0);
directionalLight.position.set( 250, 500, 250 );
directionalLight.castShadow = true;
directionalLight.shadowCameraNear = 100;
directionalLight.shadowCameraFar = 1000;
directionalLight.shadowMapWidth = 2048;
directionalLight.shadowMapHeight = 2048;
directionalLight.shadowBias = 0.0001;
directionalLight.shadowDarkness = 0.5;
directionalLight.shadowCameraLeft = -300;
directionalLight.shadowCameraRight = 300;
directionalLight.shadowCameraTop = 300;
directionalLight.shadowCameraBottom = -300;
directionalLight.shadowCameraVisible = true;
My collada objects are kind of big, so are my shadowCamera bounds.
My renderer setup:
renderer = new THREE.WebGLRenderer( {antialias: true} );
renderer.setClearColor(0x222222);
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
renderer.shadowMapType = THREE.PCFSoftShadowMap;
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
Here's another view of the scene
(mostly showing my light setup).
EDIT: Here's a snippet:
var container;
var camera, scene, renderer, controls;
var particleLight;
scene = new THREE.Scene();
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.set( 300, 100, 0 );
// Controls
controls = new THREE.OrbitControls( camera );
// Cube
var geometry = new THREE.BoxGeometry( 100, 100, 100 );
var material = new THREE.MeshLambertMaterial();
var cube = new THREE.Mesh( geometry, material );
cube.position.y = 50;
cube.rotation.y = 0.8;
cube.castShadow = true;
cube.receiveShadow = true;
scene.add( cube );
// Plane
var planeGeometry = new THREE.PlaneBufferGeometry( 300, 300, 300 );
var plane = new THREE.Mesh( planeGeometry, material );
plane.position.set( 0, 0, 0 );
plane.rotation.x = -1.6;
plane.castShadow = true;
plane.receiveShadow = true;
scene.add( plane );
// Light
var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 );
directionalLight.target.position = THREE.Vector3(0, 0, 0);
directionalLight.position.set( 250, 500, 250 );
directionalLight.castShadow = true;
directionalLight.shadowCameraNear = 100;
directionalLight.shadowCameraFar = 1000;
directionalLight.shadowMapWidth = 2048;
directionalLight.shadowMapHeight = 2048;
directionalLight.shadowBias = 0.0001;
directionalLight.shadowDarkness = 0.5;
directionalLight.shadowCameraLeft = -300;
directionalLight.shadowCameraRight = 300;
directionalLight.shadowCameraTop = 300;
directionalLight.shadowCameraBottom = -300;
directionalLight.shadowCameraVisible = true;
scene.add( directionalLight );
scene.add( new THREE.AmbientLight( 0x555555 ) );
renderer = new THREE.WebGLRenderer( {antialias: true} );
renderer.setClearColor(0x222222);
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
renderer.shadowMapType = THREE.PCFSoftShadowMap;
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
render();
}
var clock = new THREE.Clock();
function render() {
var timer = Date.now() * 0.0005;
camera.lookAt(new THREE.Vector3(0, 0, 0));
renderer.render( scene, camera );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>
Thanks in advance.
You are getting self-shadowing because the rays of the directional light are exactly parallel to some of the faces of your geometry. Move the directional light to a slightly different location. For example,
directionalLight.position.set( 250, 500, 200 );
Usually, light.shadow.bias is used to remedy self-shadowing problems, but it is not going to be effective when the light ray and face are parallel, as in your case.
Also, set shadow.bias to be negative to help alleviate artifacts on other faces.
directionalLight.shadow.bias = - 0.01;
This unfortunately will result, as it usually does, in another artifact: "Peter Panning".
These kinds of trade-offs are common. You are just going to have to find an acceptable compromise. (Maybe set the bias based on camera position.)
three.js r.75

Categories

Resources