Setting GLTF obj rotation back to original position

Hello,

Thanks for the continued support,
most of the code works as expected ,
question on setting rotation back to original position while not on the GLTF object

function render() {
	
	
	raycaster.setFromCamera( mouse, camera );

	// calculate objects intersecting the picking ray
	
	for (let i = 0; i < intersects.length; i++) {
		
		console.log("in ray picking ", intersects[0].object.name);
		
		if (intersects[0].object.name = "geo")
		{
			intersects[0].object.rotation.z += .01;
		}
		else {
			
			" rotate to the original position "
		}

	}

the above code works , i would like to set the rotation of the gltf object to its original position when the raycaster is not hitting the object

Thanks in adavance

Can you just set a variable at the start of the rotation, something like:
if(!intersects[0].object.startrotationz)
{
intersects[0].object.startrotationz=.intersects[0].object.rotation.z;
}

.....(use it in your 'else')

else {
    intersects[0].object.rotation.z=intersects[0].object.startrotationz;
    intersects[0].object.startrotationz=undefined;
}
`

Hello Thanks,

for the reply what i would like to do is set the default rotation for the specific GLTF object, when the raycaster is not on this object , because there are other Gltf objects in the scene as well,

should be straight forward, and i know i am missing something very basic,

like getting the rotation while creating this gltf object, and resetting it to this rotation , while the ray is not on this object

id like to say if the ray is not on the object name (which is working) ,
to set the rotation of the object by name to its original position
below is the code where i am trying to do this

function setDefaultRotationForModelGeo() {

		modelGeo = scene.children.getObjectByName("geo");
	
	    "reset modelGeo rotation"

			
}

raycaster.setFromCamera( mouse, camera );

    // calculate objects intersecting the picking ray

    intersects = raycaster.intersectObjects(scene.children, true);

    

    for (let i = 0; i < intersects.length; i++) {

    

        //console.log(" number of objects ", intersects.length);    

        if (intersects[i].object.name == "geo")

        {

            console.log("inside the geo object ");

            targetRotationX = mouse.y  * .05;

            intersects[i].object.rotation.z += targetRotationX;

        }

    

        setDefaultRotationForModelGeo();
      
    }

thanks

So set the startrotationz just before you start rotating, as I suggested above, and reset it like this (You only need the setting for the initial rotation just before you start to rotate, right?):

function setDefaultRotationForModelGeo() {

	    modelGeo = scene.children.getObjectByName("geo");
	
	    if(modelGeo.startrotationz)
            {
               modelGeo.rotation.z = modelGeo.startrotationz;
            }
        }

Or am I still missing your point?

Hi AJ,

thanks for the reply,

1: the scene.children.getObjectByName(“geo”) , does not work , its a GLTF object i am trying to get to ,

2: " set the startrotationz ", in the GLTF object , how do i add this variable to the GLTF object

3: it would save so much trouble if i could access the GLTF geometry by name , outside the raycasting loop, and set the default rotation here which i am unable to

4: scene.children , log return all the top level objects in the scene , like the top of the GLTF node ,
so when i call scene.children.getObjectByName(“geo”) it does not know what this is

below is how i load the GLTF object,

	const gltfLoader = new GLTFLoader();

	gltfLoader.load('models/testObj.glb', function(gltf) {

        gltf.scene.traverse(function(child) {

          if (child.isMesh) {

			  console.log(child.name);

          }

        });

        scene.add(gltf.scene);
        
	});

hey dude try giving your gltf.scene a name like so…

	const gltfLoader = new GLTFLoader();

gltfLoader.load('models/testObj.glb', function(gltf) {

    gltf.scene.traverse(function(child) {

      if (child.isMesh) {

		  console.log(child.name);

      }

    });

gltf.scene.name = "anyNameYouLike"

    scene.add(gltf.scene);
    
});

var objYouNeedToGet = scene.getObjectByName("anyNameYouLike");
console.log(objYouNeedToGet);

hopefully this should do the trick for you :slight_smile:

well , this is the problem i call it outside the loader function and it gives me undefined object,
the child name in log is fine,

everything else is fine as well , except for accessing this Gltf object by name outside the gltf loader function,

it works without any problem inside the raycaster as well

:slight_smile: am i missing something obvious ?

gltfLoader.load('models/testObj.glb', function(gltf) {

   gltf.scene.traverse(function(child) {

     if (child.isMesh) {

         console.log(child.name); //correct name

     }

   });

gltf.scene.name = "somename"

   scene.add(gltf.scene);

   

});

   objYouNeedToGet = scene.getObjectByName("somename");

   console.log(objYouNeedToGet);  // undefined object ?

even this works but not outside the loader

gltfLoader.load('models/testObj.glb', function(gltf) {

        root = gltf.scene;

        scene.add(root);

        modelFemale = root.getObjectByName('geo');

        console.log(modelFemale) // works

    });

// outside the function does not work ?

i know its something very basic and obvious , cant figure out what it is

Do you want to rotate the complete gltf scene, or only one of the meshes in the gltf scene? So can the Gltf scene have multiple meshes that can individually be rotated?

@innovate that’s odd, I did a sanity check and tested it before posting, worked outside the gltf importer for me when I did, have you made sure to call objYouNeedToGet = scene.getObjectByName("somename"); after the scene has been declared? Should do it directly after or later than scene = new THREE.scene() otherwise which three version are you using?

Hi AJ,

yes the gltf scene has several meshes , and i know the name of the mesh , and i am using this to call the mesh by name, and i get an error if i call this object by name outside the gltf loader function,
using r125

and @forerunrun well it gives me an error outside the loader function
Thanks

@innovate yes i understand but where in the code are you calling it? are you sure it’s after the scene has been created?

then

?

When you set a name to your gtft scene after it is loaded (gltf.scene.name=‘something’), then you can use your theejs scene.getObjectByName(‘something’) to get the gltf scene.
After that you can recursively inspect its children to find your mesh.
I don’t think the threejs scene.getObjectByName itself will look for meshes inside your gltf scene.

1 Like

@awonnink i think you’re right, that would have to be a traverse scene function which is kind of unnessicary outside of loading

yep that is it , you need to recursively run through its children to get the mesh , and here is where i use to find the mesh which is named “geo” in the 3d software it was exported from ,

i totally agree with you , calling scene.getObjectByName , will not get the mesh ,

and that is what i have been doing as well,

like in this example from three ,

  if (cars) {
      for (const car of cars.children) {
        car.rotation.y = time;
      }
    }

where cars is the name of the parent ,

in my case i have 2 GLTF meshes , and the geometry is mesh and its name is “geo”,
since it does not have any children,

	gltfLoader.load('models/testObj.glb', function(gltf) {

		root = gltf.scene;	
		scene.add(root);
		modelFemale = root.getObjectByName('geo');
		
		console.log(modelFemale); //Mesh
        
	});

i called it like this

function callInRender()
{
console.log(" output ", modelFemale.getObjectByName("geo"));
}

in the console first it returns an error and then displays the object its a bit funny?

Uncaught TypeError: Cannot read property ‘getObjectByName’ of undefined

and then, " output Mesh "

right that makes sense, it seems you’re running callInRender before the gltf has completely loaded, both the model has to be loaded and the scene declared before you get the output you expect, the easiest way to do this is use “loadingManager” and call “init()” “render()” and “animate()” once everything is loaded if that makes sense?

i thought when you call the init() function which has the loader , the model would be loaded ?

and then i call the render function which calls the setDefaultRotationForModelGeo function which outputs to console


function init() {

	scene = new THREE.Scene();

	const fov = 75;

	const near = .1;

	const far = 1000;

	camera = new THREE.PerspectiveCamera(fov, window.innerWidth / window.innerHeight, near, far);

	camera.position.set(0, 0, 3);

	renderer = new THREE.WebGLRenderer({ antialias: true });

	renderer.setSize(window.innerWidth, window.innerHeight);

	document.body.appendChild(renderer.domElement);

	raycaster = new THREE.Raycaster();
	
	mouse = new THREE.Vector2();

	rotateReset = new THREE.Matrix4();

	scene.add(new THREE.AmbientLight(0xffffff, 0.4));

	const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);

	directionalLight.position.set(0, 0, 4);

	scene.add(directionalLight);

	LogotextureLoader = new THREE.TextureLoader();
	Logomap = LogotextureLoader.load('images/weblogWebPage.png');
	Logomaterial = new THREE.MeshPhongMaterial({ map: Logomap });

	// Calling GLTF Loader

	const gltfLoader = new GLTFLoader();

	gltfLoader.load('models/testFObj.glb', function(gltf) {

		root = gltf.scene;	
		scene.add(root);
		modelFemale = root.getObjectByName('Female');
		
		console.log(modelFemale);
        renderer.render(scene, camera);
	});

	
	document.addEventListener( 'mousemove', onDocumentMouseMove, false );
		
}

function onDocumentMouseMove(event) {

	mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
	mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

}


function setDefaultRotationForModelGeo() {
  

	console.log(" output ", modelFemale.getObjectByName('Female'));

    }

function render() {
	
	setDefaultRotationForModelGeo();
	renderer.render(scene, camera);
}

function animate() {
	
	requestAnimationFrame(animate);
	render();

}

init();
animate();

@innovate

yeah the thing about javascript is that it’s not asynchronous in that it won’t wait for something to be loaded before it starts another task i’ll try modify your code so you get more of an understanding if it will help?

let manager;

start();

function start(){
            // LOADING MANAGER --------------------

            manager = new THREE.LoadingManager();

            manager.onStart = function ( url, itemsLoaded, itemsTotal ) {
                console.log( 'loading started');
            };

            manager.onProgress = function ( url, itemsLoaded, itemsTotal ) {
            console.log( "loading "+ url);
            };

            manager.onLoad = function ( ) {
            console.log( 'Loading complete!');
            init();
            animate();
            }; 

            manager.onError = function ( url ) {
            console.log( 'There was an error loading ' + url );     
            };

            // END OF LOADING MANAGER ---------------


        LogotextureLoader = new THREE.TextureLoader();
        Logomap = LogotextureLoader.load('images/weblogWebPage.png');
        Logomaterial = new THREE.MeshPhongMaterial({ map: Logomap });

        // Calling GLTF Loader

        const gltfLoader = new GLTFLoader();

         gltfLoader.load('models/testFObj.glb', function(gltf) {

	root = gltf.scene;	
	scene.add(root);
	modelFemale = root.getObjectByName('Female');
	
	console.log(modelFemale);
            renderer.render(scene, camera);
});
}


function init() {

scene = new THREE.Scene();

const fov = 75;

const near = .1;

const far = 1000;

camera = new THREE.PerspectiveCamera(fov, window.innerWidth / window.innerHeight, near, far);

camera.position.set(0, 0, 3);

renderer = new THREE.WebGLRenderer({ antialias: true });

renderer.setSize(window.innerWidth, window.innerHeight);

document.body.appendChild(renderer.domElement);

raycaster = new THREE.Raycaster();

mouse = new THREE.Vector2();

rotateReset = new THREE.Matrix4();

scene.add(new THREE.AmbientLight(0xffffff, 0.4));

const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);

directionalLight.position.set(0, 0, 4);

scene.add(directionalLight);




document.addEventListener( 'mousemove', onDocumentMouseMove, false );
	
}

function onDocumentMouseMove(event) {

mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

}


function setDefaultRotationForModelGeo() {


console.log(" output ", modelFemale.getObjectByName('Female'));

}

function render() {
	
	setDefaultRotationForModelGeo();
	renderer.render(scene, camera);
}

function animate() {
	
	requestAnimationFrame(animate);
	render();

}

this approach will now wait for all models to be loaded and then, as you can see in ----Loading manager---- manager.onLoad will call init() and animate() once the loading is complete

i hope this helps a bit :slight_smile:

Hi Forerunrun,

thanks a lot for the modified code, think i understand a bit , let me test run some stuff with this method,
and may be its a daft question,

function ( url, itemsLoaded, itemsTotal ),
the url , itemsLoaded,itemsTotal, should they declared somewhere ?
while testing is there an url alternative ?

i am using live server to debug

there’s no need to expicitly declare them as they are callbacks from within loading manager but you can use them as a percentage value for how many items have loaded if you need a loading icon before displaying the page like so…

    let progress = 0;

    manager.onProgress = function ( url, itemsLoaded, itemsTotal ) {
    progress = `${(itemsLoaded) / itemsTotal * 100 | 0 }`;

    loadingBar.style.left = progress + "%";

    console.log(url);
    };

as far as i’m aware as long as you pass (manager) as a callback in the loader like so…

loader = new GLTFLoader( manager );

it should create blobs from the items to be loaded and run as expected…

that brilliant, have understood a bit about the loading manager ,

so when it loads the gltf geometry it waits until the loading manger completes loading and then call the init function,
but for some reason this fails to load the geometry now, stating that the scene,add if undefined ?

here is what i have

loading started
loadManager.js:17 loading models/testFObj.glb
GLTFLoader.js:154 TypeError: Cannot read property 'add' of undefined
import * as THREE from './build/three.module.js';
import { GLTFLoader } from 'https://threejsfundamentals.org/threejs/resources/threejs/r125/examples/jsm/loaders/GLTFLoader.js';
let manager, gltfLoader, root, scene, camera, renderer, modelFemale, raycaster, mouse;

start();

function start(){
            // LOADING MANAGER --------------------

            manager = new THREE.LoadingManager();

            manager.onStart = function ( url, itemsLoaded, itemsTotal ) {
                console.log( 'loading started');
            };

            manager.onProgress = function ( url, itemsLoaded, itemsTotal ) {
            console.log( "loading "+ url);
            };

            manager.onLoad = function ( ) {
            console.log( 'Loading complete!');
            init();
            animate();
            }; 

            manager.onError = function ( ) {
            console.log( 'There was an error loading ');     
            };

            // END OF LOADING MANAGER ---------------

        // Calling GLTF Loader

        gltfLoader = new GLTFLoader(manager);

        gltfLoader.load('models/testFObj.glb', function(gltf) {

        root = gltf.scene;	
        scene.add(root);
        modelFemale = root.getObjectByName('Female');

        console.log(modelFemale);
        renderer.render(scene, camera);
});
}


function init() {

scene = new THREE.Scene();

const fov = 75;

const near = .1;

const far = 1000;

camera = new THREE.PerspectiveCamera(fov, window.innerWidth / window.innerHeight, near, far);

camera.position.set(0, 0, 3);

renderer = new THREE.WebGLRenderer({ antialias: true });

renderer.setSize(window.innerWidth, window.innerHeight);

document.body.appendChild(renderer.domElement);

raycaster = new THREE.Raycaster();

mouse = new THREE.Vector2();

scene.add(new THREE.AmbientLight(0xffffff, 0.4));

const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);

directionalLight.position.set(0, 0, 4);

scene.add(directionalLight);

document.addEventListener( 'mousemove', onDocumentMouseMove, false );
	
}

function onDocumentMouseMove(event) {

mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

}


function setDefaultRotationForModelGeo() {

    console.log(" output ", modelFemale.getObjectByName('Female'));

}

function render() {
	
	setDefaultRotationForModelGeo();
	renderer.render(scene, camera);
}

function animate() {
	
	requestAnimationFrame(animate);
	render();

}

``

found something on the docs like async and await is this related to loading as well?

Thanks