Reset GLTF position in world matrix after translation

loaders
geometry

#1

Hey there,

First time posting here, and right away I just want to say that I’ve been following along for a few weeks as a non-user, and this community is great. I’m very happy to have access to such an active and friendly group of folks during what’s undoubtedly going to be a long learning process.

I’ve successfully rescaled and repositioned a GLTF after import, and though the bounding box around the changed model is displaying at the correct position, the actual center of the object is still off. I can’t figure out how to center the model. I’m guessing it has something to do either with function scope or with failing to convert the local matrix position of the object into the global matrix outside of the loader function.

Here’s the relevant code, all inside the GLTF loader:

// Create bounding box with info on size of model, then rescale model to max size of 1
boundingBox = new THREE.Box3().setFromObject( model );
let boundingBoxSize = boundingBox.getSize( new THREE.Vector3() );
let maxAxis = Math.max( boundingBoxSize.x, boundingBoxSize.y, boundingBoxSize.z );
model.scale.multiplyScalar( 1.0 / maxAxis );


// Reset bounding box, create its center as inverted array, translate model along that array, reset bounding box
boundingBox.setFromObject(model);
let boxCenter = boundingBox.getCenter( new THREE.Vector3() );
let centerArrayInverse = [];
let centerInverse = boxCenter.multiplyScalar( -1 ).toArray(centerArrayInverse);
model.translateX( centerArrayInverse[0] );
model.translateY( centerArrayInverse[1] );
model.translateZ( centerArrayInverse[2] );
boundingBox.setFromObject(model);

Here’s an image of where the camera is pointing, using an

if (model) camera.lookAt( model.position );

in the animate():

In other words, it’s off-center - mostly on the z-axis.

If it’s easy for you to figure out: what mistake am I making here?

I’m hoping the code isn’t too confusing. Happy to take, apply, and remember any and all advice I can get.

Very happy to be learning three.js, and once I’m done with this and get it working I’ll be happy to share the complete code in a new thread for posterity.

Best,
Shane


#2

Not a huge problem anymore because I built a function which instead uses a given position within the bounding box for the camera’s lookAt()…

// Set focal position for camera orientation
// Takes three values, ideally set in closed interval between 0 and 1
setFocalPointInModel = function( rangeX, rangeY, rangeZ ) {
	let minArray = [], maxArray = [];
	boundingBox.min.toArray( minArray );
	boundingBox.max.toArray( maxArray );

	let xValue = THREE.Math.lerp( minArray[0], maxArray[0], rangeX );
	let yValue = THREE.Math.lerp( minArray[1], maxArray[1], rangeY );
	let zValue = THREE.Math.lerp( minArray[2], maxArray[2], rangeZ );

	let output = new THREE.Vector3( xValue, yValue, zValue );
	return output;
}

…but if anyone feels like responding I’d be happy to learn from you =)


#3

My guess is the model is not created so the world origin is at the models centre. Can you open the model in a 3D application program, like Blender, and recentre?


#4

I think you’re right there. I’m downloading these straight from Sketchfab, a source from which I’ve heard other people have these same problems, and I’m trying to do almost everything in Three so it can be fairly simply done with tons of models down the line.


#5

i’ve used something like this in the past:

    object.updateMatrixWorld();
    const box = new THREE.Box3().setFromObject(object);
    const size = box.getSize(new THREE.Vector3()).length();
    const center = box.getCenter(new THREE.Vector3());

    this.controls.reset();

    object.position.x += (object.position.x - center.x);
    object.position.y += (object.position.y - center.y);
    object.position.z += (object.position.z - center.z);

#6

I just replaced my convoluted inverted array function with your simpler/better position method, and that’s working. Thanks for that.

I’m still getting the same basic problem. It’s almost certainly not worthwhile for you to take the time to go in and debug my code, but one question: what does your

this.controls.reset();

do? I see it in the documentation for OrbitControls and other event-handler UI stuff, but it also gave me a breaking error when I used it inside the GLTFLoader.

Thanks for your reply here!


#7

this.controls will be an instance of OrbitControls. You don’t need this to centre your object. But it is useful for rotating around an object. If your object is at the world origin then reset will work. It changes the rotation centre to (0,0,0).


#8

Oops, I didn’t mean to copy/paste that line. It’s from an app where different models might be reloaded, and just resets OrbitControls between models.


#9

Makes sense. Thank you both for the replies and help!