Updating the rotation of a loaded model - javascript

Been futzing around with the three.js library a bit this past week, and I ran into a problem applying transformations to loaded models (gltf). Whenever I try to update the rotation I get "Uncaught TypeError: Cannot read property 'position' of undefined." I'm very confused; it seems like I can only access the .position/.rotation attributes in onLoad?
let container;
let camera;
let controls;
let renderer;
let scene;
let mesh;
const mixers = [];
const clock = new THREE.Clock();
function init() {
container = document.querySelector('#scene-container');
scene = new THREE.Scene();
scene.background = new THREE.Color(0x8FBCD4);
createCamera();
createLights();
loadModels();
createRenderer();
createControls();
renderer.setAnimationLoop(() => {
update();
render();
});
}
function createCamera() {
const fov = 35;
const aspect = container.clientWidth / container.clientHeight;
const near = 0.1; //near clipping plane
const far = 100; //far clipping plane
camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(-1.5, 1.5, 6.5);
}
function createLights() {
const ambientLight = new THREE.HemisphereLight(
0xddeeff, //bright sky color
0x202020, //dim ground color
3 //intensity
);
//this is a specular light
const mainLight = new THREE.DirectionalLight(0xffffff, 10);
mainLight.position.set(10, 10, 10);
scene.add(ambientLight, mainLight);
}
function createRenderer() {
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(container.clientWidth, container.clientHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.gammaFactor = 2.2;
renderer.gammaFactor = true;
renderer.physicallyCorrectLights = true; //allows us to use lux, candela and lumens to set lighting
container.appendChild(renderer.domElement);
}
function loadModels() {
const loader = new THREE.GLTFLoader();
const onLoad = ( gltf, position ) => {
const model = gltf.scene.children[ 0 ]; //get reference to the model
model.position.copy( position ); //passes the position parameter into the models position value
const animation = gltf.animations[ 0 ];
const mixer = new THREE.AnimationMixer( model ); //instances a animation controller
mixers.push( mixer );
const action = mixer.clipAction( animation );
action.play();
mesh = model;
scene.add( model );
};
const onProgress = () => {};
const onError = (errorMessage) => { console.log(errorMessage); };
//loads a position the model and the position
const suzannePosition = new THREE.Vector3(0, 0, 2.5);
loader.load('models/test/suzanne.glb', gltf => onLoad(gltf, suzannePosition), onProgress, onError);
}
function update() {
const delta = clock.getDelta();
for (const mixer of mixers) {
mixer.update(delta);
}
/* ---THIS DOESN'T WORK---
mesh.rotation.x += .01;
console.log(mesh.rotation);
*/
}
function createControls() {
controls = new THREE.OrbitControls(camera, container);
}
function render() {
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = container.clientWidth / container.clientHeight;
//update camera's frustum
camera.updateProjectionMatrix();
renderer.setSize(container.clientWidth, container.clientHeight);
}
window.addEventListener('resize', onWindowResize);
init();

mesh = model;
This assignment happens in the onLoad() callback of GLTFLoader.load(). It's important to understand that this callback is executed asynchronously when the model is loaded.
In the meanwhile, mesh is undefined. So change your code to the following to get rid of the runtime error:
if ( mesh ) mesh.rotation.x += .01;

Related

Change texture color Threejs(color is changed)

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

Three js, MeshStandardMaterial looks yellow

Hi i am loading a GLTF model in my scene. But the model looks too yellow i assume this has to do with the material. But i have no clue what is causing it, it is not the model itself since if i check it on donmccurdy's gltf viewer it looks perfect.
See a reference below:
GLTF Viewer:
And this is how the same model looks in my scene:
I have added an environment map to the scene this fixed may things but not the yellowness..
See current code below:
let scene, camera, renderer, controls;
let dummy = new THREE.Object3D();
let mat4 = new THREE.Matrix4();
const loader = new THREE.GLTFLoader();
let clock = new THREE.Clock();
function loadModel(url, callback) {
loader.load(
url,
function ( gltf ) {
const model = gltf.scene.children[0];
callback(model);
},
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
function ( error ) {
console.log( 'An error happened', error );
}
);
}
function generateInstances(model, count) {
const geometry = model.geometry;
geometry.scale(0.1, 0.1, 0.1);
const material = model.material;
return new THREE.InstancedMesh(geometry, material, count);
}
function setInstancePositions(instances, startPos, counts, spacing) {
if(instances.count < counts.x * counts.y * counts.z) throw Error("counts exceeds max instanciated meshes");
let index = 0;
for (let x = 0; x < counts.x; x++) {
for (let y = 0; y < counts.y; y++) {
for (let z = 0; z < counts.z; z++) {
dummy.position.addVectors(startPos, new THREE.Vector3(x * spacing.x, y * spacing.y, z * spacing.z));
dummy.updateMatrix();
instances.setMatrixAt(index, dummy.matrix);
index++;
}
}
}
return instances;
}
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(50, 75, 100);
renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
renderer.setClearColor(0xFFFFFF);
renderer.physicallyCorrectLights = true;
document.body.appendChild(renderer.domElement);
new THREE.RGBELoader()
.load('assets/enviroment.hdr', function ( texture ) {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = texture;
});
let controls = new THREE.OrbitControls(camera, renderer.domElement);
const light1 = new THREE.AmbientLight(0xffffff, 0.3);
light1.name = 'ambient_light';
scene.add( light1 );
loadModel('assets/100-dollars.glb', (model) => {
let instances = generateInstances(model, 1500);
instances = setInstancePositions(instances, new THREE.Vector3(), new THREE.Vector3(5, 30, 10), new THREE.Vector3(27, 3, 13));
scene.add(instances);
});
renderer.setAnimationLoop(() => {
camera.lookAt(scene.position);
renderer.render(scene, camera);
});
}
init();
here is the hdr file: url
and here is the model: url
Using GLTFLoader requires a sRGB workflow which is not configured in your app. Add the following line and see if it fixes the color issue:
renderer.outputEncoding = THREE.sRGBEncoding;
Besides, consider to turn on antialiasing and the usage of setPixelRatio() for better quality:
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio);

How to create a mesh out of an imported model in Three.js

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

How to load objects with Three.js with high quality?

I'm trying to create an object loader with Three.js but I noticed that the quality is way too low and used too much CPU at the same time.
When I use my version, the scene looks like this:
But when I use this website to load it, looks so much better and uses less CPU:
My JavaScript to load this object is:
var camera;
var scene;
var renderer;
var controls;
var container = document.getElementById('webgl');
var WIDTH = container.clientWidth;
var HEIGHT = container.clientHeight;
var ASPECT = WIDTH / HEIGHT;
var ANGLE = 45;
var container = document.getElementById('webgl');
if (Detector.webgl) {
main();
} else {
var warning = Detector.getWebGLErrorMessage();
document.getElementById('webgl').appendChild(warning);
}
function main(){
//Scene
scene = new THREE.Scene();
//Camera
camera = new THREE.PerspectiveCamera(
ANGLE, // field of view
ASPECT, // aspect ratio
10, // near clipping plane
100000 // far clipping plane
);
camera.position.x = 500;
camera.position.y = 200;
camera.position.z = 500;
camera.lookAt(new THREE.Vector3(100, 100, 100));
//Renderer
renderer = new THREE.WebGLRenderer();
var ambientLight = getAmbientLigth(1);
scene.add(ambientLight);
scene.background = new THREE.Color( 0xc3c3c3 );
renderer.setSize(WIDTH, HEIGHT);
renderer.shadowMap.enabled = true;
document.getElementById('webgl').appendChild(renderer.domElement);
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.maxPolarAngle = Math.PI/2;
controls.enableKeys = true;
loadObject();
update(renderer, scene, camera, controls);
}
function getAmbientLigth(intensity, color) {
color = color === undefined ? 'rgb(255, 255, 255)' : color;
var light = new THREE.AmbientLight(color, intensity);
return light;
}
function loadObject() {
var mtlLoader = new THREE.MTLLoader();
var objLoader = new THREE.OBJLoader();
mtlLoader.setPath( 'objects/Blue_shed/' );
mtlLoader.load('blueShed.mtl', function( materials ) {
materials.isMultiMaterial = true;
materials.preload();
objLoader.setMaterials( materials );
objLoader.setPath( 'objects/Blue_shed/' );
objLoader.load( 'blueShed.obj', function ( object ) {
object.name = 'cute-house';
object.receiveShadow = true;
object.castShadow = true;
object.scale.set( 30, 30, 30);
scene.add( object );
} );
});
}
function update(renderer, scene, camera, controls) {
controls.update();
renderer.render(scene, camera);
requestAnimationFrame(function() {
update(renderer, scene, camera, controls);
});
}
I used renderer.setSize to increase the resolution of the renderer and that helped a little bit but still is not as good as in the second image, and still uses too much CPU.
Any ideas? Is there a setting or something that I'm not setting up correctly? I see that website uses a JSON loader, but I don't think that has something to do with this issue, but I mention it just in case.

i want to load a .obj file and change its texture/material at run-time by button click using three.js

each time i wants to load load my model and change its texture the model not loading, and there is nothing in the screen. i am a noob in three.js/webgl languages and javascript. please help me to proceed with right information.
here is the following code.
https://drive.google.com/open?id=0BxJJ7XpRqKz4S3JONlAwSHJxdFk this link provides the assets im using in this projects.
// once everything is loaded, we run our Three.js stuff.
function init() {
var stats = initStats();
// create a scene, that will hold all our elements such as objects, cameras and lights.
var scene = new THREE.Scene();
// create a camera, which defines where we're looking at.
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
// create a render and set the size
var webGLRenderer = new THREE.WebGLRenderer();
webGLRenderer.setClearColor(new THREE.Color(0xaaaaff, 1.0));
webGLRenderer.setSize(window.innerWidth, window.innerHeight);
webGLRenderer.shadowMapEnabled = true;
// position and point the camera to the center of the scene
camera.position.x = 100;
camera.position.y = 40;
camera.position.z = 50;
camera.lookAt(scene.position);
scene.add(camera);
// add spotlight for the shadows
var spotLight = new THREE.DirectionalLight(0xfa93e5);
spotLight.position.set(30, 40, 50);
spotLight.intensity = 0.5;
scene.add(spotLight);
// add the output of the renderer to the html element
document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);
// call the render function
var step = 0;
// setup the control gui
var controls = new function () {
// we need the first child, since it's a multimaterial
};
var gui = new dat.GUI();
//model
var loader = new THREE.OBJLoader();
loader.load( 'sofa 1.obj', function (object) );
var sofa = new THREE.Mesh(object,fabric_1);
var texture = new THREE.ImageUtils.loadTexture("defaultMat_Base_Color(1).png");
var texture2 = new THREE.ImageUtils.loadTexture("defaultMat_Base_Color_1.png");
var material = THREE.ImageUtils.loadTexture("defaultMat_Normal_DirectX bump.png");
var material1 = THREE.ImageUtils.loadTexture("sofa new final4 high-AO_u0_v0.png");
var material2 = THREE.ImageUtils.loadTexture("lambert2SG_Roughness specular.png");
var fabric_1 = new THREE.MeshPhongMaterial(
{ fabric_1.map = texture;
fabric_1.normalMap = material;
fabric_1.aoMap = material1;
fabric_1.specularMap = material2; });
var fabric_2 = new THREE.MeshPhongMaterial(
{ fabric_2.map = texture_2;
fabric_2.normalMap = material;
fabric_2.aoMap = material1;
fabric_2.specularMap = material2;
});
scene.add(sofa),
function setfabric_1 () {
sofa.traverse(function(child){
if(child instanceof THREE.Mesh){
child.material = fabric_1;
}
sofa.geometry.uvsNeedUpdate = true;
sofa.needsupdate = true;
});
}
function setfabric_2 () {
sofa.traverse(function(child){
if(child instanceof THREE.Mesh){
child.material = fabric_2;
}
sofa.geometry.uvsNeedUpdate = true;
sofa.needsupdate = true;
});
}
render();
function render() {
stats.update();
if (mesh) {
mesh.rotation.y += 0.006;
;
}
// render using requestAnimationFrame
requestAnimationFrame(render);
webGLRenderer.render(scene, camera);
}
function initStats() {
var stats = new Stats();
stats.setMode(0); // 0: fps, 1: ms
// Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.getElementById("Stats-output").appendChild(stats.domElement);
return stats;
}
}
window.onload = init;
Use uniforms to link local variables to the shader, make sure you preload the textures first though. threejs.org/uniforms. Better yet use
"uTexArray" : { type: "tv", value: [ new THREE.Texture(), new THREE.Texture() ] } // texture array (regular)
enter link description here

Categories