How to rotate a gltf model in a specific direction

I have a gltf model in my scene that I want to rotate(in a specific direction) whenever there is inactivity for a certain amount of time. I’ve been researching this for a while and I only find help when the object is a cube and not an actual gltf file. Here is my code

var scene = new THREE.Scene(); 

// Load Camera Perspektive
var camera = new THREE.PerspectiveCamera( 100, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.set( 1, 1, 150 );//the position of the object x,y,z

// Load a Renderer
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

window.addEventListener('resize', function(){


    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
})

// Load the Orbitcontroller
var controls = new THREE.OrbitControls( camera, renderer.domElement );

// Load Light
var ambientLight = new THREE.AmbientLight( 0x404040 );//provides light to an object
scene.add( ambientLight );

var directionalLight = new THREE.DirectionalLight( 0xffffff );//like the sun, light in specific direction
directionalLight.position.set( 0, 1, 1 ).normalize();
scene.add( directionalLight );

        var loader = new THREE.GLTFLoader();

        loader.load(
// resource URL
'models/gltf/head/glTF/scene.gltf',
// called when the resource is loaded
function ( gltf ) {

    scene.add( gltf.scene );



},
// called when loading is in progresses
function ( xhr ) {

    console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );

},
// called when loading has errors
function ( error ) {

    console.log( 'An error happened' );

}

);

     function animate(){

         requestAnimationFrame(animate);

         renderer.render(scene, camera);
     }

animate();

I can’t see from your code where your are rotating anything - keep a reference to the model as model = gltf.scene, and then you can change model.rotation exactly as if it were a cube or any other kind of mesh. Once a mesh has been loaded, it doesn’t matter where it came from.

3 Likes

@donmccurdy
It’s cross-posting of this SO question:
https://stackoverflow.com/q/50420083/4045502

1 Like

Thank you, So if I wanted it to rotate after a certain interval, how about I go about that?

The gist is something like this:

var model;

loader.load( 'foo.gltf', function ( gltf ) {
  model = gltf.scene;
  scene.add(model);
});

// ... later, in animate or render function ...
if (model) model.rotation.x += 0.01;

For a more specific answer you will need to show the code you are using to attempt rotation now, and any errors you see.

4 Likes

Thank u great code!!

This works but it’s giving me a “Cannot read property ‘position’ of undefined” error. My gltf model is given ‘car’ as an identifier. It’s reference in the animate function is when I get the error.

		var scene, camera, renderer;



	function init() {

		scene = new THREE.Scene();
		camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
		
		scene.background = new THREE.Color( 0xefefef );


		// Camera

		camera.position.set( 10, 10, 10 );
		


		// Lighting

		var directionalLight = new THREE.DirectionalLight( 0xffffff, 2 );
		directionalLight.position.set( -12, 10, -8 );
		scene.add( directionalLight );

		var light = new THREE.PointLight( 0xffffff, 1.5, 0, 2 );
		light.position.set( 0, 8, 0.5 );
		scene.add( light );





		// Render 

		renderer = new THREE.WebGLRenderer( { antialias: true } );
		renderer.setSize( window.innerWidth, window.innerHeight );
		document.getElementById("grid").appendChild(renderer.domElement);
		renderer.shadowMap.enabled = true;
		renderer.shadowMap.type = THREE.BasicShadowMap;

		// Resize to the size of the screen
		window.addEventListener('resize', function() {

			var width = window.innerWidth;
			var height = window.innerHeight;
			renderer.setSize( width, height );
			camera.aspect = width / height;
			camera.updateProjectionMatrix();


		});



		var car;
		var carLoader = new THREE.GLTFLoader();
		carLoader.load("scenes/bp_scene_6_car.gltf", function ( gltf ) {


			car = gltf.scene;
		    scene.add( car );


		});




		controls = new THREE.OrbitControls( camera, renderer.domElement );


		var size = 10;
		var divisions = 10;

		var gridHelper = new THREE.GridHelper( size, divisions );
		scene.add( gridHelper );




		function animate() {



			requestAnimationFrame(animate);

			car.position.y = 0;	

			renderer.render(scene, camera);





		}

		animate();


	}





	init();

You’ll need to wait for the car to load before trying to animate it. For example,

if (car) car.position.y = 0;

Even better, if it’s just a one-time thing, set the position in the loader callback rather than in the animate function.

1 Like

Brilliant! Thanks Don

Could you let me know what is wrong here?

<script>
        init();
        animate();

        function init() {
            var scene = new THREE.Scene();
            var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
            var renderer = new THREE.WebGLRenderer({
                alpha: true
            });
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.outputEncoding = THREE.sRGBEncoding;
            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();
            })

            stats = new Stats();
            document.body.appendChild(stats.dom);

            controls = new THREE.OrbitControls(camera, renderer.domElement);

            var AmbientLight = new THREE.AmbientLight(0xFFFFFF, 1);
            scene.add(AmbientLight);

            var pointLight = new THREE.PointLight(0xffffff, 0.7);
            pointLight.position.set(0, 3, 0);
            scene.add(pointLight);

            var light = new THREE.DirectionalLight(0xffffff, 1);
            light.position.set(0, 20, 30);
            light.castShadow = true;
            scene.add(light);

            // envmap
            var path = 'js/';
            var format = '.jpg';
            var envMap = new THREE.CubeTextureLoader().load([
                path + 'posx' + format, path + 'negx' + format,
                path + 'posy' + format, path + 'negy' + format,
                path + 'posz' + format, path + 'negz' + format
            ]);



            var dracoLoader = new DRACOLoader();
            dracoLoader.setDecoderPath('js/');

            var loader = new THREE.GLTFLoader();
            loader.setDRACOLoader(dracoLoader);
            loader.load('js/object.glb', function(gltf) {

                var model = gltf.scene;
                model.position.set(0, 0, 0);
                model.rotation.y = Math.PI / 2;
                model.scale.set(0.05, 0.05, 0.05);
                model.traverse(function(child) {
                    if (child.isMesh) child.material.envMAp = envMap;
                });

                scene.add(model);

            }, undefined, function(error) {

                console.error(error);

            });

            camera.position.z = 10

        }

        function animate() {
            requestAnimationFrame(animate);

            render();
            stats.update();

        }

        function render() {

            if (model !== null) {
                model.rotation.x += 0.01;
                model.rotation.y += 0.01;

                renderer.render(scene, camera);
            }
        }
    </script>

Thank You!

A live example would be helpful.
Did you see the girl’s spin?

see LoadGLTFmove

Thanks for the link – There is no spin in it though.

I don’t think I understand what you actually need. :thinking:


In my example
view-source:LoadGLTFmove
the model is rotated with gltf.scene.rotation.set( 0, yRotation, 0 );.

Since it is not centered, you have to calculate the desired position afterwards.

gltf.scene.position.set( xPosition - cx, size.y / 2 - c.y, zPosition - cz );

I have tried like that as well but the model disappeared when I did.

if (model) {
            model.rotation.x += 0.01;
            model.rotation.y += 0.01;
        }

This is how my fashion plate spins.

<!DOCTYPE html>
<!-- -->
<head>
	<title> LoadGLTF </title>
	<meta charset="utf-8" />
	<style>
	body {
	overflow: hidden;
	margin: 0;
	}
	</style>
</head>
<body> </body>

<script src="../js/three.min.115.js"></script>
<script src="../js/OrbitControls.115.js"></script>
<script src="../js/GLTFLoader.115.js"></script>

<script>

'use strict'
 
const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.01, 1000 );
camera.position.set( 0, 2, 8 );

const renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
renderer.setClearColor( 0xaaaaaa, 1 );

const controls = new THREE.OrbitControls( camera, renderer.domElement );

const gridHelper = new THREE.GridHelper( 10, 10 );
scene.add( gridHelper );

const lightA = new THREE.AmbientLight( 0x404040 ); // soft white light
scene.add( lightA );

const lightP = new THREE.PointLight( 0xddff00, 1  );
lightP.position.set( -1, 3, 5 );
scene.add( lightP );

// --- data input ---
let yRotation = 3.21; 
let xPosition = -1.5;	 
let zPosition = 3.1;
// -----         ----- 

const loader = new THREE.GLTFLoader( );

// konta johanna remix (CC-BY)   people (license)
// https://poly.google.com/view/7PNIMdmMSPD
loader.load( 'girl/google poly.gltf', process );

let model, c, size; // model center and size  

animate();

function animate( ) {

	requestAnimationFrame( animate );
	yRotation += 0.01;
	move( model );
	renderer.render( scene, camera );

}

function process( gltf ) {	
		
	const box = new THREE.Box3( ).setFromObject( gltf.scene );		 
	const boxHelper = new THREE.Box3Helper( box, 0xffff00 );
    scene.add( boxHelper );
	
	c = box.getCenter( new THREE.Vector3( ) );
	size = box.getSize( new THREE.Vector3( ) );
	
	move( gltf );

	scene.add( gltf.scene );
	
	model = gltf;

}
 
function move( gltf ) {

	gltf.scene.rotation.set( 0, yRotation, 0 );
	
	// rotate center
	const cz = c.z * Math.cos( yRotation ) - c.x * Math.sin( yRotation );
	const cx = c.z * Math.sin( yRotation ) + c.x * Math.cos( yRotation );
	
	gltf.scene.position.set( xPosition - cx, size.y / 2 - c.y, zPosition - cz );

}
	
</script>

</html>

I’m not good at writing js – thanks for sharing :smiley:

I found this – Looks funny ::: Three.js - Load .GLTF - Rotate Cars

No problem at all. :slightly_smiling_face:

Perhaps it would help to look at some basic examples.

There are a few that fit.
Collection of examples from discourse.threejs.org


With this enhancement the lady moves additionally sideways.

let model, c, size; // model center and size
let t = 0;
let x0 = xPosition;
let dx;

animate();

function animate( ) {
	
	requestAnimationFrame( animate );
	yRotation += 0.005;
	
	t += 0.001;
	dx = Math.sin( t )
	
	xPosition = x0 +  dx;
	
	move( model );
	renderer.render( scene, camera );
	
}
1 Like

I’m looking – Can you tell me the name of the rotating rabbit three js page?

Got it! Yeah! :smiley:

I have changed the example somewhat. This makes it clearer and makes less calculation effort when moving the model.

UPDATED: https://hofk.de/main/discourse.threejs/2020/LoadGLTF/LoadGLTF.html

<!DOCTYPE html>
<!-- https://discourse.threejs.org/t/how-to-rotate-a-gltf-model-in-a-specific-direction/2881/18 -->
<head>
	<title> LoadGLTFmove </title>
	<meta charset="utf-8" />
	<style>
	body {
	overflow: hidden;
	margin: 0;
	}
	</style>
</head>
<body> </body>

<script src="../js/three.min.115.js"></script>
<script src="../js/OrbitControls.115.js"></script>
<script src="../js/GLTFLoader.115.js"></script>

<script>

'use strict'

// @author hofk
 
const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.01, 1000 );
camera.position.set( 0, 2, 8 );

const renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
renderer.setClearColor( 0xaaaaaa, 1 );

const controls = new THREE.OrbitControls( camera, renderer.domElement );

const gridHelper = new THREE.GridHelper( 10, 10 );
scene.add( gridHelper );

const lightA = new THREE.AmbientLight( 0x404040 ); // soft white light
scene.add( lightA );

const lightP = new THREE.PointLight( 0xddff00, 1  );
lightP.position.set( -1, 3, 5 );
scene.add( lightP );

// --- data input ---
let yRotation =  0; 
let xPosition = -1.2;	 
let zPosition =  3.5;
// -----         ----- 

const loader = new THREE.GLTFLoader( );

// konta johanna remix (CC-BY)   people (license)
// https://poly.google.com/view/7PNIMdmMSPD
loader.load( 'girl/google poly.gltf', process );

let model = new THREE.Object3D( );
let c, size; // model center and size
 
let t = 0;
let x0 = xPosition;
let dx;

animate();

function animate( ) {
	
	requestAnimationFrame( animate );
	
	yRotation += 0.005;	
	t += 0.001;
	dx = Math.sin( t )	
	xPosition = x0 + dx;	
 	
	model.rotation.y = yRotation;
	
	model.position.x = xPosition;
	model.position.z = zPosition;
		
	renderer.render( scene, camera );
	
}

function process( gltf ) {	
		
	const box = new THREE.Box3( ).setFromObject( gltf.scene );		 
	const boxHelper = new THREE.Box3Helper( box, 0xffff00 );
    scene.add( boxHelper );
	
	c = box.getCenter( new THREE.Vector3( ) );
	size = box.getSize( new THREE.Vector3( ) );
	
	gltf.scene.position.set( -c.x, size.y / 2 - c.y, -c.z );

	model.add( gltf.scene );
	
	scene.add( model );
	
} 
	
</script>

</html>