I am new to Three.js. I am having issues using a gltf model as the actual scene and not part of the scene in three.js. The gltf model is an apartment. I want the scene to load from inside the apartment and not outside the apartment. the controls should work within the apartment too. So far, I have loaded the model on the scene but I can't get the scene to render from inside the model.
Here is my code in Typescript and also JavaScript been at it for weeks now. Any help will be much appreciated. Thank you so much.
Typescript code
import * as THREE from '/build/three.module.js'
import { OrbitControls } from '/jsm/controls/OrbitControls'
import { GLTFLoader } from '/jsm/loaders/GLTFLoader'
import Stats from '/jsm/libs/stats.module'
const scene: THREE.Scene = new THREE.Scene()
const axesHelper = new THREE.AxesHelper(5)
//scene.add(axesHelper)
var light = new THREE.SpotLight();
light.position.set(5, 5, 5)
scene.add(light);
const camera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.z = 2
const renderer: THREE.WebGLRenderer = new THREE.WebGLRenderer()
//renderer.physicallyCorrectLights = true
//renderer.shadowMap.enabled = true
renderer.outputEncoding = THREE.sRGBEncoding
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
const controls = new OrbitControls(camera, renderer.domElement)
const loader = new GLTFLoader()
loader.load(
'apartment.glb',
function (gltf) {
// gltf.scene.traverse(function (child) {
// if ((<THREE.Mesh>child).isMesh) {
// let m = <THREE.Mesh>child
// m.receiveShadow = true
// m.castShadow = true
// }
// if ((<THREE.Light>child).isLight) {
// let l = <THREE.Light>child
// l.castShadow = true
// //l.shadow.bias = -.003
// l.shadow.mapSize.width = 2048
// l.shadow.mapSize.height = 2048
// }
// })
scene.add(gltf.scene);
},
(xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded')
},
(error) => {
console.log(error);
}
);
window.addEventListener('resize', onWindowResize, false)
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
render()
}
const stats = Stats()
document.body.appendChild(stats.dom)
var animate = function () {
requestAnimationFrame(animate)
controls.update()
render()
stats.update()
};
function render() {
renderer.render(scene, camera)
}
animate();
JavaScript code
import * as THREE from '/build/three.module.js';
import { OrbitControls } from '/jsm/controls/OrbitControls';
import { GLTFLoader } from '/jsm/loaders/GLTFLoader';
import Stats from '/jsm/libs/stats.module';
const scene = new THREE.Scene();
const axesHelper = new THREE.AxesHelper(5);
//scene.add(axesHelper)
var light = new THREE.SpotLight();
light.position.set(5, 5, 5);
scene.add(light);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 2;
const renderer = new THREE.WebGLRenderer();
//renderer.physicallyCorrectLights = true
//renderer.shadowMap.enabled = true
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
const loader = new GLTFLoader();
loader.load('apartment.glb', function (gltf) {
// gltf.scene.traverse(function (child) {
// if ((<THREE.Mesh>child).isMesh) {
// let m = <THREE.Mesh>child
// m.receiveShadow = true
// m.castShadow = true
// }
// if ((<THREE.Light>child).isLight) {
// let l = <THREE.Light>child
// l.castShadow = true
// //l.shadow.bias = -.003
// l.shadow.mapSize.width = 2048
// l.shadow.mapSize.height = 2048
// }
// })
scene.add(gltf.scene);
}, (xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
}, (error) => {
console.log(error);
});
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render();
}
const stats = Stats();
document.body.appendChild(stats.dom);
var animate = function () {
requestAnimationFrame(animate);
controls.update();
render();
stats.update();
};
function render() {
renderer.render(scene, camera);
}
animate();
Finally was able to solve my issue.
firstly I had to use a plane model that is with no roof
secondly the pivot point was properly at the center and the model was on the plane grid, unlike the first model I was working with.
with the model opened the room was what was rendered in the scene and not the entire model itself and because the pivot point was in the middle and the model on the plane, not below or above it, I did not have to look for it in the scene when it rendered. Thank you for reading and trying to help.
because I had solved this problem I was able to load multiple glb models and place them where I wanted in the scene without hassle.
my advice if you want to use a model as your scene make sure the pivot point is at the center and the model is on the grid, not over or below it. also make sure its an open model so your light and camera can see inside.
here was my final code.
import * as THREE from '/build/three.module.js'
import { OrbitControls } from '/jsm/controls/OrbitControls'
import { GLTFLoader } from '/jsm/loaders/GLTFLoader'
// import Stats from '/jsm/libs/stats.module'
// import { GUI } from '/jsm/libs/dat.gui.module'
const scene: THREE.Scene = new THREE.Scene()
const axesHelper = new THREE.AxesHelper(5)
//scene.add(axesHelper)
const light = new THREE.SpotLight(0xffa95c,4);
light.position.set(-50,50,50);
light.castShadow = true;
scene.add( light );
var hemiLight = new THREE.HemisphereLight(0xffeeb1, 0x080820, 4);
scene.add(hemiLight);
var light3 = new THREE.DirectionalLight( 0xffffff );
light3.position.set( 0, 200, 100 );
light3.castShadow = true;
light3.shadow.mapSize.width = 2048;
light3.shadow.mapSize.height = 2048;
light3.shadow.camera.top = 3000;
light3.shadow.camera.bottom = -3000;
light3.shadow.camera.left = -3000;
light3.shadow.camera.right = 3000;
light3.shadow.camera.far = 3000;
scene.add( light );
const camera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.z = 2
camera.position.y = 2
camera.position.x = 2
const renderer: THREE.WebGLRenderer = new THREE.WebGLRenderer()
//renderer.physicallyCorrectLights = true
//renderer.shadowMap.enabled = true
renderer.outputEncoding = THREE.sRGBEncoding
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
// var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2000, 2000 ), new THREE.MeshPhongMaterial( { color: 0x999999, depthWrite: false } ) );
// mesh.rotation.x = - Math.PI / 2;
// //mesh.position.y = -100;
// mesh.receiveShadow = true;
// //this.scene.add( mesh );
// var grid = new THREE.GridHelper( 2000, 40, 0x000000, 0x000000 );
// //grid.position.y = -100;
// // grid.material.opacity = 0.2;
// // grid.material.transparent = true;
const raycaster = new THREE.Raycaster();
const controls = new OrbitControls(camera, renderer.domElement)
controls.screenSpacePanning = true
controls.target.set(0, 1, 0)
controls.minDistance = 5;
controls.maxDistance = 10;
// const backGroundTexture = new THREE.CubeTextureLoader().load(["img/py_eso0932a.jpg", "img/ny_eso0932a.jpg", "img/py_eso0932a.jpg", "img/ny_eso0932a.jpg", "img/pz_eso0932a.jpg", "img/nz_eso0932a.jpg"]);
// scene.background = backGroundTexture;
const loader = new GLTFLoader()
loader.load(
'models3/untitled.glb',
function (gltf) {
scene.add(gltf.scene);
gltf.scene.position.set(0,-2,3)
},
(xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded')
},
(error) => {
console.log(error);
}
);
loader.load(
'models3/man.glb',
function (gltf1) {
scene.add(gltf1.scene);
gltf1.scene.position.set(1,-1.3,0)
gltf1.scene.scale.set(2,2,2)
},
(xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded')
},
(error) => {
console.log(error);
}
);
loader.load(
'models3/jack_daniels.glb',
function (gltf2) {
gltf2.scene.traverse(function (child) {
if ((<THREE.Mesh>child).isMesh) {
let m = <THREE.Mesh>child
m.receiveShadow = true
m.castShadow = true;
//(<THREE.MeshStandardMaterial>m.material).flatShading = true
//sceneMeshes.push(m)
}
if ((<THREE.Light>child).isLight) {
let l = <THREE.Light>child
l.castShadow = true
l.shadow.bias = -.003
l.shadow.mapSize.width = 2048
l.shadow.mapSize.height = 2048
}
scene.add(gltf2.scene);
gltf2.scene.position.set(-1,0.55,-1)
gltf2.scene.scale.set(0.15,0.15,0.15)})
},
(xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded')
},
(error) => {
console.log(error);
}
);
// renderer.domElement.addEventListener('dblclick', onDoubleClick, false);
// renderer.domElement.addEventListener('mousemove', onMouseMove, false);
// function onMouseMove(event: MouseEvent) {
// const mouse = {
// x: (event.clientX / renderer.domElement.clientWidth) * 2 - 1,
// y: -(event.clientY / renderer.domElement.clientHeight) * 2 + 1
// }
// //console.log(mouse)
// raycaster.setFromCamera(mouse, camera);
window.addEventListener('resize', onWindowResize, false)
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
render()
}
// const stats = Stats()
// document.body.appendChild(stats.dom)
var animate = function () {
requestAnimationFrame(animate)
// light.position.set(
// camera.position.x + 10,
// camera.position.y + 10,
// camera.position.z + 10,
// );
controls.update()
render()
// stats.update()
};
function render() {
renderer.render(scene, camera)
}
animate();
function onDoubleClick(arg0: string, onDoubleClick: any, arg2: boolean) {
throw new Error('Function not implemented.')
}
PLEASE FEEL FREE TO COMMENT IF THERE IS SOMETHING I NEED TO KNOW. I WILL HUMBLY TAKE CORRECTIONS. THANK YOU
Related
I am trying to make the imported obj model to move with the help of three.js, but due to formatting problem, the obj object must be declared inside a function, and i am not able to access it outside the function, even if i pre-declared a variable outside the function to point to thee object. How can i access the object in this way?
import * as THREE from 'https://unpkg.com/three#0.126.1/build/three.module.js';
import { OrbitControls } from 'https://unpkg.com/three#0.126.1/examples/jsm/controls/OrbitControls.js';
import {OBJLoader} from "https://unpkg.com/three#0.126.1/examples/jsm/loaders/OBJLoader.js";
import {MTLLoader} from "https://unpkg.com/three#0.126.1/examples/jsm/loaders/MTLLoader.js";
import * as GUI from "https://unpkg.com/dat.gui#0.7.7/build/dat.gui.module.js";
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
var keyLight = new THREE.DirectionalLight(new THREE.Color('hsl(30,100%,75%)'),1.0);
var fillLight = new THREE.DirectionalLight(new THREE.Color('hsl(240,100%,75%)'),0.75);
var backLight = new THREE.DirectionalLight(0xffffff,1.0);
keyLight.position.set(-100,0,100);
fillLight.position.set(100,0,100);
backLight.position.set(100,0,-100).normalize();
scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth/window.innerHeight,
0.1,
1000
);
const planeGeometry = new THREE.PlaneGeometry(100,100);
const planeMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff,
wireframe: false,
});
var plane = new THREE.Mesh(planeGeometry,planeMaterial);
scene.add(plane);
plane.rotation.x = -0.5 * Math.PI;
const gridHelper = new THREE.GridHelper(100);
scene.add(gridHelper);
const gui = new GUI.GUI();
const options = {
planeColor: '#ffea00',
wireframe: false
};
gui.addColor(options,'planeColor').onChange(function(e){
plane.material.color.set(e);
});
gui.add(options,'wireframe').onChange(function(e){
plane.material.wireframe = e;
});
const orbit = new OrbitControls(camera,renderer.domElement);
camera.position.set(0,2,7.5);
orbit.update();
const spotLight = new THREE.SpotLight(0xffffff);
scene.add(spotLight);
spotLight.position.set(-50,50,0);
spotLight.castShadow = true;
spotLight.angle = 0.2;
const sLightHelper = new THREE.SpotLightHelper(spotLight);
scene.add(sLightHelper);
gui.add(spotLight,"angle",-1,1,0.01).name("angle");
gui.add(spotLight,"penumbra",0,1,0.01).name("penumbra");
gui.add(spotLight,"intensity",0,100,0.01).name("Intensity");
let house = undefined;
const mtlLoader = new MTLLoader();
mtlLoader.load(
'../source/MaryStanfordLifeboatHouse02.mtl',
(materials)=>{
materials.preload();
console.log(materials);
const objLoader = new OBJLoader()
objLoader.setMaterials(materials)
objLoader.load(
'../source/MaryStanfordLifeboatHouse02.obj',
function(object){
scene.add(object);
house = object;
house.rotation.x = 1/2 * Math.PI;
house.rotation.y = Math.PI;
},
function(xhr){
console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
},
function(error){
console.log("Object error")
}
)
},
(xhr) => {
console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
},
(error) => {
console.log("Material Eror")
}
)
const textureLoader = new THREE.TextureLoader();
textureLoader.load(
'../img/doge.jpg',
function ( texture ) {
scene.background = texture;
},
undefined,
function ( err ) {
console.error( 'An error happened.' );
}
);
function animate(){
// house.position.x += 1;
renderer.render(scene,camera);
sLightHelper.update();
}
renderer.setAnimationLoop(animate);
window.addEventListener('resize',function(){
camera.aspect = window.innerWidth/this.window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth,window.innerHeight);
});
// house.position.x += 1;
This line breaks because you access the variable too early. Keep in mind that the model is loaded asynchronously and you have to honor this circumstance when accessing it. As simple fix to avoid runtime errors is:
if ( house !== undefined ) house.position.x += 1;
Another option is that you only start animating when all assets have been loaded.
I am currently trying to change the geometry of a cube in three js to that of a sphere after a certain time interval or an event click. I have tried to change the property of geometry from Three.BoxGeometry to Three.SphereGeometry but have had no luck.
I have also tried to implement some "solutions" that I found, but have hit a wall there too.
Here is what I initially had:
export class ThreeJSService {
geometry: THREE.BoxGeometry;
camera: THREE.PerspectiveCamera;
cube: THREE.Mesh;
movingObject;
renderer: THREE.WebGLRenderer;
scene: THREE.Scene;
texture: THREE.Texture;
/**
* Setups scene for 3d objects
*/
constructor() {
this.scene = new THREE.Scene();
this.texture = new THREE.TextureLoader().load('assets/apartment_background.png');
this.scene.background = this.texture;
this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
this.renderer = new THREE.WebGLRenderer();
this.geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);
const material = new THREE.MeshBasicMaterial( {color: 0x348713} );
this.cube = new THREE.Mesh( this.geometry, material );
this.movingObject = {
object: this.cube,
geometry: this.geometry,
direction: {
x: 0.03,
y: 0,
},
};
}
/**
* Sets all the requirements needed for the scene
* #param {HTMLElement} parent The element to attach to
*/
setup(parent: HTMLElement) {
const canvas = this.renderer.domElement;
this.scene.add( this.cube );
this.camera.position.z = 5;
parent.appendChild(canvas);
}
// transform() {
// for ( var i = 0, l = this.geometry.vertices.length; i < l; i ++ ) {
//
// var vertex = this.geometry.vertices[ i ];
// vertex.normalize().multiplyScalar( 550 );
//
// // After a certain interval change the geometry from Cylinder to Sphere
//
// }
// }
/**
* Provides animation to the rendered object. Makes the cube move and sends it to another direction when getting to the border
* #param {number | undefined} headerHeight The height of the header
*/
animate() {
const header = document.getElementById('header')?.clientHeight;
this.renderer.setSize( window.innerWidth, window.innerHeight - (header ? header : 0));
this.movingObject.object.rotateX(0.01);
this.movingObject.object.rotateY(0.01);
requestAnimationFrame( this.animate.bind(this) );
this.renderer.render( this.scene, this.camera );
this.movingObject.object.position.x += this.movingObject.direction.x;
// Check if the position of the cube is on the border
if (this.cube.position.x > 7.3 || this.cube.position.x < -7.3) {
this.movingObject.direction.x = -this.movingObject.direction.x;
}
}
Any help would be greatly appreciated!
Here is a complete live example that shows a geometry is replaced after two seconds.
let camera, scene, renderer;
init();
render();
function init() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.set(2, 2, 2);
camera.lookAt(0, 0, 0);
scene = new THREE.Scene();
geometry = new THREE.BoxGeometry();
material = new THREE.MeshNormalMaterial();
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
setTimeout(function() {
mesh.geometry.dispose();
mesh.geometry = new THREE.SphereGeometry();
render();
}, 2000);
}
function render() {
renderer.render(scene, camera);
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.141/build/three.min.js"></script>
I managed to get it to work.
This is my solution:
changeShape() {
this.interval = (Math.floor(Math.random() * (400 + 1)) * 1000);
// this.interval = Math.floor((Math.random() * (20 - 10 + 10)) + 10) * 1000;
if (this.switch) {
setTimeout(() => {
this.movingObject.object.geometry.dispose();
this.movingObject.object.geometry = new THREE.CylinderGeometry(0.5, 0.5, 2);
this.switch = false;
// console.log(this.interval);
}, this.interval);
} else {
setTimeout(() => {
this.movingObject.object.geometry.dispose();
this.movingObject.object.geometry = new THREE.SphereGeometry(0.5, 8, 8);
this.switch = true;
// console.log(this.interval);
}, this.interval);
}
}
Thank you for the assist!
Here is worked test repo
I have a black texture for my 3D model
And I want to change color for this texture, to brown(0x964B00)
Initially model looks like this
But after adding color it looks like color of texture was blended with color which I added, but I want it to have appearance with color with I set.
Here is how it looks
But I want it to have this color
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ alpha: true });
const ambientLight = new THREE.AmbientLight(0xcccccc, 0.4);
scene.add( ambientLight );
const pointLight = new THREE.PointLight(0xffffff, 0.8);
camera.add(pointLight);
scene.add(camera);
const container3D = '3d-container'
renderer.setSize(window.innerWidth, window.innerHeight);
const element = document.getElementById(container3D)
element.appendChild(renderer.domElement);
const texture1Diff1Url = '/textures/armchair/black/tableLegs_black.dif.jpg'
const texture1Ref1Url = '/textures/armchair/black/tableLegs_black.ref.jpg'
const texture1Diff = new THREE.TextureLoader().load(texture1Diff1Url);
const texture1Ref = new THREE.TextureLoader().load(texture1Ref1Url);
const tex3DiffUrl = '/textures/armchair/black/cloth_black01.dif.jpg'
const tex3RefUrl = '/textures/armchair/black/cloth_black01.ref.jpg'
const texture3Diff = new THREE.TextureLoader().load(tex3DiffUrl);
const texture3Ref = new THREE.TextureLoader().load(tex3RefUrl);
const objLoader = new THREE.OBJLoader();
const objUrl = '/armchair.obj'
const controls = new THREE.OrbitControls( camera, renderer.domElement );
objLoader
.load(objUrl, function (object) {
const scaleFactor = 0.015
object.scale.set(scaleFactor, scaleFactor, scaleFactor);
camera.position.x = 0;
camera.position.y = 8;
camera.position.z = 20;
const legs = object.children[0]
const base1 = object.children[1]
const base2 = object.children[2]
legs.material.map = texture1Diff;
legs.material.specularMap = texture1Ref;
base1.material.map = texture3Diff;
base1.material.specularMap = texture3Ref;
// here I set color
const colorHex = 0x964B00
base1.material.color.setHex(colorHex)
scene.add(object);
animate()
},
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
function ( error ) {
console.log( 'An error happened' );
}
);
controls.target.set( 0, 0.5, 0 );
controls.update();
controls.enablePan = false;
controls.enableDamping = true;
window.onresize = function () {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
};
function animate() {
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
};
Any suggestion will be helpful
Im trying to create a game using three.js, but I'm running into some issues regarding the imported 3D models. I've created them in Blender and used the gltf-blender-IO plugin to make it easier to work with. However, I can't exactly move the model without it being a mesh. How do I create a mesh out of the model in order to fix this issue?
The full code is here.
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);
window.addEventListener("resize", function() {
var width = window.innerWidth;
var height = window.innerHeight;
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
});
// controls = new THREE.OrbitControls(camera, renderer.domElement);
renderer.shadowMap.enabled = true;
renderer.shadowMapSoft = true;
renderer.physicallyCorrectLights = true;
camera.position.z = 3;
// ambient light
var ambientLight = new THREE.AmbientLight(0xF0F0F0, 4.5);
scene.add(ambientLight);
// directional light
var directionalLight = new THREE.DirectionalLight(0xffffff, 5.0);
directionalLight.position.set(5, 0, 5);
directionalLight.target.position.set(0, 0, 0);
directionalLight.castShadow = true;
directionalLight.shadowDarkness = 0.5;
directionalLight.shadowCameraNear = 0;
directionalLight.shadowCameraFar = 15;
directionalLight.shadowCameraLeft = -5;
directionalLight.shadowCameraRight = 5;
directionalLight.shadowCameraTop = 5;
directionalLight.shadowCameraBottom = -5;
scene.add(directionalLight);
// Load a glTF resource
var loader = new THREE.GLTFLoader;
loader.load(
'Fox.glb',
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
},
// called while loading is progressing
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
// called when loading has errors
function ( error ) {
console.log( 'An error happened' );
}
);
// end main
function update() {
};
function render() {
renderer.render(scene, camera);
};
function loop() {
window.requestAnimationFrame(loop);
update();
render();
}
loop();
I am new to using three.js. I used to use a JSON file as my 3D model but the actual 3D file has some issues when I export it from Blender so I am switching to obj. The actual model is fine now but I have no idea how to switch from JSON to obj. This is as far as I can get but I keep getting the error: THREE.Object3D.add: object not an instance of THREE.Object3D.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
10,
1000
);
camera.position.z = 100;
camera.position.y = 10;
var renderer = new THREE.WebGLRenderer({
alpha: true
});
var manager = new THREE.LoadingManager(loadModel);
manager.onProgress = function(item, loaded, total) {
console.log(item, loaded, total);
};
var wrapper = new THREE.Object3D();
var textureloader = new THREE.TextureLoader();
renderer.setSize(window.innerWidth, window.innerHeight);
var light = new THREE.DirectionalLight(0xffffff, 1.0);
light.position.set(100, 100, 100);
scene.add(light);
var light2 = new THREE.DirectionalLight(0xffffff, 1.0);
light2.position.set(-100, 100, -100);
scene.add(light2);
function onError() {}
function onProgress(xhr) {
if (xhr.lengthComputable) {
var percentComplete = (xhr.loaded / xhr.total) * 100;
console.log("model " + Math.round(percentComplete, 2) + "% downloaded");
}
}
var head;
var loader = new THREE.OBJLoader2(manager);
loader.load(
"http://trhidouan309.barzalou.com/site_web/js/profil.obj",
function(obj) {
head = obj;
},
onProgress,
onError
);
function loadModel() {
setTimeout(function() {
wrapper.add(head);
scene.add(wrapper);
}, 10);
}
material.opacity = 0.6;
var hiddenPlane = new THREE.Mesh(planeGeometry, material);
hiddenPlane.position.set(0, 0, 50);
scene.add(hiddenPlane);
var mouse = new THREE.Vector2(0, 0);
var point = new THREE.Vector3(0, 0, 0);
var raycaster = new THREE.Raycaster();
camera.lookAt(scene.position);
window.addEventListener("mousemove", onMouseMove, false);
window.addEventListener("resize", onWindowResize, false);
function onMouseMove(event) {
event.preventDefault();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObject(hiddenPlane);
if (intersects.length > 0) {
point = intersects[0].point;
}
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
wrapper.lookAt(point);
renderer.render(scene, camera);
}
window.onload = function() {
document.getElementById("scene3d").appendChild(renderer.domElement);
};
animate();
<script src="js/LoaderSupport.js"></script>
<script src="js/OBJLoader2.js"></script>
<script src="js/index.js"></script>
The 3D model seems to load but I don't think its able to be added in the scene
You are having issues with the timing of the calls to load the obj file and render it.
You are calling loadModel through the loading manager which contains a call to the object named head before it is initialized by loader.load() function. Additionally you are calling loader.load() asynchronously which would cause further timing issues.
One way to fix this would be calling loader.load() synchronously by passing the correct arguments as mentioned in the docs OBJLoader2 ThreeJS (see below) and moving the call to loader.load to be before the loading manager so that it would load before the object named head gets used.
From objloader2 doc setting useAsync to false causes the loader to load synchronously:
.load ( url : String, onLoad : Function, onProgress : Function, onError : Function, onMeshAlter : Function, useAsync : boolean ) : null
This way ensures the obj object is not used before the .obj file is loaded.
See code snippet below:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 10, 1000);
camera.position.z = 100;
camera.position.y = 10;
var renderer = new THREE.WebGLRenderer({
alpha: true
});
//Moved loader.load and passed correct sync args
var head;
var loader = new THREE.OBJLoader2(manager);
loader.load('http://trhidouan309.barzalou.com/site_web/js/profil.obj', function (obj) {
head = obj;
}, onProgress, onError, null, false);
var manager = new THREE.LoadingManager(loadModel);
manager.onProgress = function (item, loaded, total) {
console.log(item, loaded, total);
};
var wrapper = new THREE.Object3D;
var textureloader = new THREE.TextureLoader();
renderer.setSize(window.innerWidth, window.innerHeight);
var light = new THREE.DirectionalLight(0xffffff, 1.0);
light.position.set(100, 100, 100);
scene.add(light);
var light2 = new THREE.DirectionalLight(0xffffff, 1.0);
light2.position.set(-100, 100, -100);
scene.add(light2);
function onError() {}
function onProgress(xhr) {
if (xhr.lengthComputable) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log('model ' + Math.round(percentComplete, 2) + '% downloaded');
}
}
function loadModel() {
setTimeout(function () {
wrapper.add(head);
scene.add(wrapper);
}, 10);
}
material.opacity = 0.6;
var hiddenPlane = new THREE.Mesh(planeGeometry, material);
hiddenPlane.position.set(0, 0, 50);
scene.add(hiddenPlane);
var mouse = new THREE.Vector2(0, 0);
var point = new THREE.Vector3(0, 0, 0);
var raycaster = new THREE.Raycaster();
camera.lookAt(scene.position);
window.addEventListener('mousemove', onMouseMove, false);
window.addEventListener('resize', onWindowResize, false);
function onMouseMove(event) {
event.preventDefault();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObject(hiddenPlane);
if (intersects.length > 0) {
point = intersects[0].point;
}
};
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
wrapper.lookAt(point);
renderer.render(scene, camera);
}
window.onload = function () {
document.getElementById("scene3d").appendChild(renderer.domElement);
}
animate();
PS: there seems to be another issue with material.opacity = 0.6; lacking correct declaration that might cause the scene to not render properly.