How to load a glb file in three.js - three.js

My goal is to run a website locally with the back-written in flask and the front end with three.js, everything works fine because i do not see any errors in the console (devtools) but for some reason it is not showing the model, I have the camera, scene and render, I also loaded the model and added to the scene
<body>
<script src="https://threejs.org/build/three.js" >
import * as THREE from 'three';
let scene, camera, renderer, stats, model;
const loader;
camera = new THREE.PerspectiveCamera(75, window.Width / window.Height, 0.1, 1000);
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.Width, window.Height);
document.body.appendChild(renderer.domElement);
loader = new GLTFLoader();
loader.load( "{{ url_for('static', filename='free_1975_porsche_911_930_turbo.glb') }}",
function ( gltf ) {
scene.add( gltf.scene );
gltf.animations; // Array<THREE.AnimationClip>
gltf.scene; // THREE.Group
gltf.scenes; // Array<THREE.Group>
gltf.cameras; // Array<THREE.Camera>
gltf.asset;
},
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
function ( error ) {
console.error( error );
}
);
function animate()
{
requestAnimationFrame( animate );
renderer.render( scene, camera );
};
animate();
</script>
</body>
why isn't this code showing the model in the browser
the model from sketchfab

Related

OrbitControls.js -- handleMouseMoveRotate is not a function

I am trying to have my camera pan around a skybox using mouse movement. I am using three.js and OrbitControls.js. Please take a look at my code snippets below.
<!DOCTYPE html>
<html>
<head>
<meta charset=UTF-8 />
<link rel="stylesheet" type="text/css" href="styles.css" />
</head>
<body>
<script type="module">
import * as THREE from 'https://cdn.jsdelivr.net/npm/three#0.121.1/build/three.module.js';
import { DRACOLoader } from 'https://cdn.jsdelivr.net/npm/three#0.121.1/examples/jsm/loaders/DRACOLoader.js';
import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three#0.121.1/examples/jsm/controls/OrbitControls.js';
let scene, camera, renderer;
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(55,window.innerWidth/window.innerHeight,45,30000);
camera.position.set(-900,-200,-900);
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);
let controls = new OrbitControls(camera, renderer.domElement)
controls.dispose();
controls.update();
document.addEventListener('mousemove', onDocumentMouseMove, false);
function onDocumentMouseMove(event) {
// Manually fire the event in OrbitControls
controls.handleMouseMoveRotate(event);
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
controls.update();
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
let materialArray = [];
let texture_ft = new THREE.TextureLoader().load( 'front.png');
let texture_bk = new THREE.TextureLoader().load( 'back.png');
let texture_up = new THREE.TextureLoader().load( 'up.png');
let texture_dn = new THREE.TextureLoader().load( 'down.png');
let texture_rt = new THREE.TextureLoader().load( 'right.png');
let texture_lf = new THREE.TextureLoader().load( 'left.png');
materialArray.push(new THREE.MeshBasicMaterial( { map: texture_ft }));
materialArray.push(new THREE.MeshBasicMaterial( { map: texture_bk }));
materialArray.push(new THREE.MeshBasicMaterial( { map: texture_up }));
materialArray.push(new THREE.MeshBasicMaterial( { map: texture_dn }));
materialArray.push(new THREE.MeshBasicMaterial( { map: texture_rt }));
materialArray.push(new THREE.MeshBasicMaterial( { map: texture_lf }));
for (let i = 0; i < 6; i++)
materialArray[i].side = THREE.BackSide;
let skyboxGeo = new THREE.BoxGeometry( 10000, 10000, 10000);
let skybox = new THREE.Mesh( skyboxGeo, materialArray );
scene.add( skybox );
animate();
}
function animate() {
renderer.render(scene,camera);
requestAnimationFrame(animate);
}
init();
</script>
</body>
</html>
I have updated OrbitControl.js as such:
this.handleMouseMoveRotate = function ( event ) {
rotateEnd.set( event.clientX, event.clientY );
rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
const element = scope.domElement;
rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
rotateStart.copy( rotateEnd );
scope.update();
}
However, I am receiving the error:
236(index):36 Uncaught TypeError: controls.handleMouseMoveRotate is not a function at HTMLDocument.onDocumentMouseMove ((index):36:10)
I know mouse movement is being detected as I see it firing as I move across the screen. What am I doing wrong?
Edit: I've updated the index.html file to point to a local copy of OrbitControls (with the edit I made)
You're right, I forgot to change that back to a local version. However, now I receive:
Uncaught TypeError: Failed to resolve module specifier "three". Relative references must start with either "/", "./", or "../".
This is a problem with Javascript scoping. You're declaring controls inside of init(), so it's not available inside onDocumentMouseMove().
let scene;
function init() {
let controls = new OrbitControls();
scene = new Scene();
}
function onDocumentMouseMove() {
// Controls does not exist here
controls.dosomething();
// But scene does exist
scene.add(xxyyzz);
}
Just declare the variable up one level to increase its scope, like you do with scene, camera, renderer. Then it should be accessible within your functions.

glb/gltf Model not loading on Netlify, but loads locally

I am using Three.js with the gltf loader to load a single .glb resource onto a page. It works locally, though then I upload to Netlify the model does not load and the xhr progressEvent's total is 0. I checked that the model is still being loaded in the network tab, but yet it still does not show in the page.
It seems this problem has occurred before, but not sure how to resolve it when using Netlify if there are any environment variables I need to change.
https://github.com/mrdoob/three.js/issues/15584
HTML
<div class="model-wrapper">
<div id="model_target" class="loading">
<div class="myimage fade" id="placeholder">
<img src="images/placeholder.png" height="328px"/></div>
</div>
</div>
<!-- THREE.js -->
<script src="https://threejs.org/build/three.js"></script>
<!-- GLTFLoader.js -->
<script src="https://cdn.rawgit.com/mrdoob/three.js/r92/examples/js/loaders/GLTFLoader.js"></script>
JS
```
let camera, scene, renderer;
const mouse = new THREE.Vector2();
const look = new THREE.Vector2();
const windowHalf = new THREE.Vector2( window.innerWidth /
2, window.innerHeight / 2 );
var plane = new THREE.Plane(new THREE.Vector3(0, 0, 0.4),
-9);
var raycaster = new THREE.Raycaster();
var pointOfIntersection = new THREE.Vector3();
let modelLoaded = false;
let placement = document.getElementById("model_target")
window.addEventListener('DOMContentLoaded', init);
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 60, 1, 1, 1000);
camera.position.set(5, 3, 28)
//camera.position.y = 13;
var light = new THREE.DirectionalLight("#fff", 1.5);
var ambient = new THREE.AmbientLight("#FFF");
light.position.set( 0, -70, 100 ).normalize();
scene.add(light);
// scene.add(ambient);
var texture = new THREE.Texture();
var loader = new THREE.GLTFLoader();
THREE.Cache.enabled = true;
// Load a glTF resource
loader.load(
// 3d model resource
'./assets/models/mrktechy3.glb',
// called when the resource is loaded
function ( gltf ) {
mesh = gltf.scene;
mesh.scale.set( 5, 5, 5 );
scene.add( mesh );
},
// called when loading is in progress
function ( xhr ) {
// Loading progress of model
console.log(xhr);
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
if((xhr.loaded / xhr.total * 100) == 100){
modelLoaded = true;
//Loading overlay
var placeholder = document.getElementById("placeholder");
placeholder.classList.add("faded");
placement.classList.remove("loading");
}
},
// called when loading has errors
function ( error ) {
console.log( 'An error happened' );
}
);
//scene.background = new THREE.Color(0xfff); //Set background color
renderer = new THREE.WebGLRenderer( { alpha: true, antialias: true } );
renderer.setSize( 800, 500 );
placement.appendChild( renderer.domElement );
renderer.setClearColor(0x000000, 0);
renderer.gammaOutput = true;
document.addEventListener( 'mousemove', onMouseMove, false );
window.addEventListener( 'resize', onResize, false );
render()
}
function onMouseMove( event ) {
if (modelLoaded){
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 0;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 0;
raycaster.setFromCamera(mouse, camera);
raycaster.ray.intersectPlane(plane, pointOfIntersection);
mesh.lookAt(pointOfIntersection);
}
}
function onResize( event ) {
const width = 800 ;
const height = 500;
windowHalf.set( width / 2, height / 2 );
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( width, height );
}
var easeAmount = 8;
function update(){
look.x += (mouse.x-look.x)/easeAmount;
look.y += (mouse.y-look.y)/easeAmount;
raycaster.setFromCamera(look, camera);
raycaster.ray.intersectPlane(plane, pointOfIntersection);
mesh.lookAt(pointOfIntersection);
}
function render() {
camera.aspect = renderer.domElement.clientWidth / renderer.domElement.clientHeight;
camera.updateProjectionMatrix();
requestAnimationFrame( render );
if (modelLoaded){
update();
}
renderer.render( scene, camera );
}
```
Any glb resource can be replaced in the code and it works locally but not when hosted.
In the IIS settings, try to add mime type for gltf. Something like this:
application/gltf-buffer .gltf
This solved my problem.

Three JS - GLTF model is dark

I have succeeded to load my model into ThreeJS using GLTFLoader but my model is dark. I tried uploading it to glTF Viewer and BabylonJS and it works perfectly there. Here is my javascript code:
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 )
const controls = new THREE.OrbitControls( camera )
const light = new THREE.AmbientLight( 0x404040 ); // soft white light
const renderer = new THREE.WebGLRenderer()
renderer.setSize( window.innerWidth, window.innerHeight )
renderer.setClearColor( 0xffffff )
document.body.appendChild( renderer.domElement )
// Instantiate a loader
const loader = new THREE.GLTFLoader();
// Load a glTF resource
loader.load(
// resource URL
'untitled2.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
}
// loading and error function
)
camera.position.y = 1
camera.position.z = 2
// Vertical
controls.minPolarAngle = 1; // radians
controls.maxPolarAngle = 1; // radians
//Horizontal
controls.minAzimuthAngle = - Infinity; // radians
controls.maxAzimuthAngle = Infinity; // radians
scene.add( light );
const animate = function () {
requestAnimationFrame( animate )
renderer.render( scene, camera )
}
animate()
I tried adding ambient lighting because according to the documentation it is supposed to act as global illumination and changing the background color.
Here is when I upload the model to babylonJS:
Here is when I upload the model to glTF viewer:
And here is when I load it to ThreeJS (it's dark):
Solved it finally! The solution was that I needed to add intensity to the ambient light.

ThreeJS - GLTF loaded but not appearing

I loaded a GLTF in ThreeJS, and I see in the console GLTFLoader: 37.4208984375ms, but it's not showing up in the scene, and I don't understand why. Also, I used some boilerplate from the ThreeJS website. Here's what the code looks like:
var camera, scene, renderer;
var geometry, material, mesh;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
camera.position.set(20,0,20);
scene = new THREE.Scene();
// Instantiate a loader
var loader = new THREE.GLTFLoader();
// Load a glTF resource
loader.load( 'Box.gltf', 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>
} );
var light = new THREE.AmbientLight(0xffffff);
scene.add(light);
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
So what am I doing wrong here? Am I missing something?
Two problems:
Your camera is inside your model. Move it farther away.
You call render() only once, long before your model is added to the scene. Call render in a requestAnimationFrame, which is in every Three.js example.

Apply MeshBasicMaterial to loaded obj+mtl with Three.js

When I load obj+mtl+jpg data with Three.js, the material of the object is set to MeshLambertMaterial according to three.js document. If I want to change the material to another one such as MeshBasicMaterial, how can I do that?
The following code loads obj+mtl+jpg from my server and display the data with MeshLambertMaterial. I tried to apply MeshBasicMaterial with the following code (commented), but it failed and the object with displayed in white.
<!DOCTYPE html>
<html lang="ja">
<head><meta charset="UTF-8"></head>
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/loaders/MTLLoader.js"></script>
<script src="http://threejs.org/examples/js/loaders/OBJMTLLoader.js"></script>
<body>
<div id="canvas_frame"></div>
<script>
var canvasFrame, scene, renderer, camera;
canvasFrame = document.getElementById('canvas_frame');
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
canvasFrame.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set(50,50,50);
camera.lookAt( {x: 0, y: 0, z: 0} );
var ambient = new THREE.AmbientLight(0xFFFFFF);
scene.add(ambient);
function animate() {
renderer.render( scene, camera );
requestAnimationFrame( animate );
}
function loadObjMtl(objUrl, mtlUrl, url, x, y, z){
var loader = new THREE.OBJMTLLoader();
loader.crossOrigin = 'anonymous';
loader.load( objUrl, mtlUrl,
function ( object ) {
object.url = url;
object.position.set(x,y,z);
object.traverse( function( node ) {
if( node.material ) {
////This doesn't work. How can I apply material for loaded obj?
//var material = new THREE.MeshBasicMaterial();
//if ( node instanceof THREE.Mesh ) {
// node.material = material;
//}
}
});
scene.add ( object );
});
}
objUrl = "http://test2.psychic-vr-lab.com/temp/mesh_reduced.obj";
mtlUrl = "http://test2.psychic-vr-lab.com/temp/mesh_reduced.mtl";
loadObjMtl(objUrl,mtlUrl,"",0,0,0);
animate();
</script>
</body>
</html>
You see it totally white because you are not specifying any color for MeshBasicMaterial.
Try this:
var material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
You'll see all red: it is working.
I think that you probably want to distinguish the different meshes, or apply any texture, do you?
I know this is an old question but I was looking to do something similar and did it this way:
As of today Three.js r143 , the MTLLoader loads the materials as MeshPhongMaterial as seen in
MTLLoader.js 495: this.materials[ materialName ] = new MeshPhongMaterial( params );
Because I didn't want any reflections from my lighting. So I set the materials to
MeshLambertMaterial (see the docs) by just changing that line to:
MTLLoader.js 495: this.materials[ materialName ] = new MeshLambertMaterial( params );
And that's it!.
I know this approach will change the way every other model is loaded but in my case that's how I wanted it.
Hope this helps

Resources