Jump to content

Set Pivot on rotated/scaled mesh


Numa
 Share

Recommended Posts

Hi there, 

I'm trying to rotate a mesh around a specific point. I use the setPivotMatrix + translate back and it works great, as long as the mesh isn't already scaled or rotated. If it is, the mesh jumps to a wrong position before it starts rotating.

I took care of the scale but can't figure out how to handle the rotation. Here's what I have:

    
    var position = new BABYLON.Vector3(10, 10, 10);

    // Mesh position relative to pivot point
    var relativePosition = mesh.position.subtract(position);

    // Set pivot matrix
    mesh.setPivotMatrix(BABYLON.Matrix.Translation(relativePosition.x * (1 / mesh.scaling.x),
                                                   relativePosition.y * (1 / mesh.scaling.y),
                                                   relativePosition.z * (1 / mesh.scaling.z)));

    // Translate back
    mesh.position = mesh.position.add(new BABYLON.Vector3(-relativePosition.x,
                                                          -relativePosition.y,
                                                          -relativePosition.z));

 

Thanks guys

Link to comment
Share on other sites

@Numa and @DigiHz Data after days playing around with setPivotMatrix I suddenly felt very foolish as I realised the approach was wrong and I had in fact produced the basis of a solution back in May 2015 in the post below (back in the days when I was new to BJS and was misinterpreting many things and was working on an un-necessary solution to something dealt with much easier - so nothing changes does it)

However as wrong headed as that solution was it was the solution to the pivot problem.

Here are two methods one for rotating around a pivot and one for scaling from a pivot both of which allow you to move the pivot and the mesh using just .position. If you would both like to test them out and see if they fail anywhere this would be very useful. (After all I though I had found a solution previously and it failed). 

Of course anyone else is welcome to test them out as well.

The Rotation Method

rotateAroundPivot takes three parameters - the position of the pivot (Vector3), an axis (Vector3)  to rotate around and the angle (number as radians) to rotate. Rotations are accumulative.

BABYLON.Mesh.prototype.rotateAroundPivot = function(pivotPoint, axis, angle) {
		if(!this._rq) {
			this._rq = BABYLON.Quaternion.Identity();
		}		
		var _p = new BABYLON.Quaternion(this.position.x - pivotPoint.x, this.position.y - pivotPoint.y, this.position.z - pivotPoint.z, 0);
		axis.normalize();
		var _q = BABYLON.Quaternion.RotationAxis(axis,angle);  //form quaternion rotation		
		var _qinv = BABYLON.Quaternion.Inverse(_q);	
		var _pdash = _q.multiply(_p).multiply(_qinv);
		this.position = new BABYLON.Vector3(pivotPoint.x + _pdash.x, pivotPoint.y + _pdash.y, pivotPoint.z + _pdash.z);
		this.rotationQuaternion = this._rq.multiply(_q);
		this._rq = this.rotationQuaternion;
	}

 

Scaling Method

scaleFromPivot takes four parameters the position of the pivot (Vector3) and the scale for x, y, z axes as numbers. The numbers used set the current scale of the mesh based on its original size with the pivot as centre of enlargement.

BABYLON.Mesh.prototype.scaleFromPivot = function(pivotPoint, sx, sy, sz) {
		var _sx = sx / this.scaling.x;
		var _sy = sy / this.scaling.y;
		var _sz = sz / this.scaling.z;
		this.scaling = new BABYLON.Vector3(sx, sy, sz);	
		this.position = new BABYLON.Vector3(pivotPoint.x + _sx * (this.position.x - pivotPoint.x), pivotPoint.y + _sy * (this.position.y - pivotPoint.y), pivotPoint.z + _sz * (this.position.z - pivotPoint.z));
	}

Here is a playground to try it out

http://www.babylonjs-playground.com/#1MKHR9

Link to comment
Share on other sites

@Numa thank you for pointing this out. I had assumed that my methods would be applied from the start and all rotations would take place using them. In practice your correction would only work if previous rotations had been done using mesh.rotate. If a rotation was set just using mesh.rotation then this.rotationQuaternion would be undefined.

Hopefully between us we now have it working correctly in all cases using the modified code below.

BABYLON.Mesh.prototype.rotateAroundPivot = function(pivotPoint, axis, angle) {
	if(!this._rotationQuaternion) {
	     this._rq = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
	}		
	var _p = new BABYLON.Quaternion(this.position.x - pivotPoint.x, this.position.y - pivotPoint.y, this.position.z - pivotPoint.z, 0);
	axis.normalize();
	var _q = BABYLON.Quaternion.RotationAxis(axis,angle);  //form quaternion rotation		
	var _qinv = BABYLON.Quaternion.Inverse(_q);	
	var _pdash = _q.multiply(_p).multiply(_qinv);
	this.position = new BABYLON.Vector3(pivotPoint.x + _pdash.x, pivotPoint.y + _pdash.y, pivotPoint.z + _pdash.z);
	this.rotationQuaternion = this._rq.multiply(_q);
	this._rq = this.rotationQuaternion;
}

New PG http://www.babylonjs-playground.com/#1MKHR9#1

Please feel free to test again and once more thank you for the feedback.

Link to comment
Share on other sites

  • 1 year later...

Hi here,

I'm planning to make a rubik's cube with babylon. I'm new to babylon and javascript.

I'm using your function to rotate the face around the cube axis.

Here is my playground : http://www.babylonjs-playground.com/#1MKHR9#62

The "u" key rotate the upper face.

The "r" key rotate the right face.

As long as I rotate only the upper face or only the right face, everything is ok.

But, if you press "u" once, then "r" once, some pieces rotate both around the world axis (as i wish) AND around the piece axis.

I really don't understand why because I only use your function RotateAroundPivot once .

Do someone have an idea why ?

Thanks.

JMB

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...