ThreeJS - Trouble loading FBX file - javascript

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.

Related

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

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

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/

Multiple STL files on single web page using threeJS

Here I have one STL file that I am displaying with threeJS. I don't know how to render multiple STL Files in single web page.
Here's my code:
var container, camera, scene, renderer;
init();
animate();
function init() {
container = document.getElementById('pratik');
document.body.appendChild( container );
// renderer
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 3, 0.5, 3 );
scene.add( camera ); // required, because we are adding a light as a child of the camera
// Controls
controls = new THREE.OrbitControls( camera, renderer.domElement );
// lights
scene.add( new THREE.AmbientLight( 0x222222 ) );
var light = new THREE.PointLight( 0xffffff, 0.8 );
camera.add( light );
// object
var loader = new THREE.STLLoader();
loader.load( 'files/wolf.stl', function ( geometry ) {
var material = new THREE.MeshPhongMaterial( { color: 0xff5533 } );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
} );
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();
}
function render() {
var timer = Date.now() * 0.0005;
camera.position.x = Math.cos( timer ) * 15;
camera.position.z = Math.sin( timer ) * 15;
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
<div id="pratik"></div>
Now what if I need to include another file named 'mk6.stl', How will I do it?
Does anyone knows how to do it?
I have tried SketchFan, but its not made for me.
Thank you.
You already have the code to load a single STL file and insert it into your scene. The next step to load multiple files is straightforward, you would simply reuse your STLLoader instance. Basically you could do something like:
var loader = new THREE.STLLoader();
loader.load( 'FIRSTFILE.stl', function ( geometry ) {
var material = new THREE.MeshPhongMaterial( { color: 0xff5533 } );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
} );
loader.load( 'SECONDFILE.stl', function ( geometry ) {
var material = new THREE.MeshPhongMaterial( { color: 0xff5533 } );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
} );
You could also use the loaders load() method in a loop if you have an array of URLs to load your STL-files from.

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

imported 3D objects are not casting shadows with three.js

I'm currently wrapping my brain around three.js and I've imported 3d model I made in C4D via the three.OBJMTLLoader successfully, but I can't get the object to cast a shadow. I've used object.castShadow = true but its not working but I can get geometry created in three.js to cast a shadow so I know the scene is setup ok.
The test scene is currently here: http://kirkd.co.uk/dev/ and has now been updated with the fix suggested below.
The code is below, if someone could kindly point out either what I'm doing wrong or even if imported objects can cast shadows then I'd be eternally grateful.
Ta.
<script>
var container;
var controls;
var camera, scene, renderer;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000);
camera.position.z = 500;
camera.position.y = 500;
scene = new THREE.Scene();
controls = new THREE.OrbitControls( camera );
controls.addEventListener( 'change', render );
var ambientLight = new THREE.AmbientLight(0x0c0c0c);
scene.add(ambientLight);
var spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set( 500, 1000, 500 );
spotLight.castShadow = true;
spotLight.shadowMapWidth = 1024;
spotLight.shadowMapHeight = 1024;
scene.add( spotLight );
var companion = new THREE.OBJMTLLoader();
companion.load( 'companion2.obj', 'companion.mtl', function ( object ) {
object.position.set(0,-20,0);
object.scale.set( 0.8, 0.8, 0.8 );
object.castShadow = true;
scene.add( object );
});
var floorGeometry = new THREE.CubeGeometry(1000,4,1000);
var floorMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});
var floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.position.x=0;
floor.position.y=-130;
floor.position.z=0;
floor.receiveShadow = true;
scene.add(floor);
var geometry = new THREE.BoxGeometry( 100, 100, 100 );
mesh = new THREE.Mesh( geometry);
scene.add( mesh );
mesh.position.set(-100,200,10);
mesh.castShadow = true;
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xEEEEEE, 1.0);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild( renderer.domElement );
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
spotLight.shadowCameraVisible = true;
var step=0;
render();
};
function render() {
camera.lookAt(scene.position);
renderer.render(scene, camera);
}
function animate() {
requestAnimationFrame( animate );
render();
}
</script>
Your object has child meshes, each of which needs to have castShadow set to true.
In your loader callback, add this:
object.traverse( function( node ) { if ( node instanceof THREE.Mesh ) { node.castShadow = true; } } );
three.js r.66

Categories

Resources