Jump to content

Moving and rotate a physic object from a newbie


Arthuron
 Share

Recommended Posts

Hi guys,

Iam a newbie and thats my first question here. I have some little trouble with my first steps with babylonJS.
My english skills not the best but i hope u undertand what i want, i will explain it with some of my code snippets.

 
var scene = new BABYLON.Scene(engine);
scene.enablePhysics();
var camera = new BABYLON.ArcRotateCamera("Camera", 3 * Math.PI / 2, Math.PI / 8, 50, BABYLON.Vector3.Zero(), scene);
camera.attachControl(engine.getRenderingCanvas(), false);

// Hemispheric light to light the scene
var h = new BABYLON.HemisphericLight("hemi", new BABYLON.Vector3(0, 1, 0), scene);
h.groundColor = BABYLON.Color3.FromInts(255, 83, 13);
h.intensity = 0.5;

// Ground creation
var ground = BABYLON.Mesh.CreateGround("ground", 100, 100, 1, scene);
ground.position.y = -11;
ground.receiveShadows = true;
ground.setPhysicsState(BABYLON.PhysicsEngine.BoxImpostor, {mass: 0, restitution: 0.5, friction: 0.1});

// Material
var matPlan = new BABYLON.StandardMaterial("matPlan1", scene);
matPlan.backFaceCulling = false;
matPlan.emissiveColor = new BABYLON.Color3(1.2, 1, 0.2);
var plan = BABYLON.Mesh.CreateBox("plane2", 20, scene);
plan.position = new BABYLON.Vector3(20, 0, 0);
plan.setPhysicsState(BABYLON.PhysicsEngine.BoxImpostor, {mass: 1, restitution: 0.5, friction: 0.1});
plan.material = matPlan;

// Balloon - Thats my Player
balloon = BABYLON.Mesh.CreateBox("balloon", 2, scene);
balloon.position = new BABYLON.Vector3(0, -10, 0);
balloon.rotation.y = 1;
balloon.body = balloon.setPhysicsState(BABYLON.PhysicsEngine.BoxImpostor, {mass: 1, friction: 0.001, restitution: 0.5});
balloon.material = new BABYLON.StandardMaterial("matBallon", scene);
balloon.material.emissiveColor = new BABYLON.Color3(1, 1, 1);

So, you can see i add a big yellow cube and small white one on a ground in this scene.

Now i add some key event listeners and the functions from the physics example by temechon (btw. i write him a mail with this question.but i think he is a busy man).
scene.registerBeforeRender(function () {
   oKeyBoard.fxKeyEvents("w");
   oKeyBoard.fxKeyEvents("d");
   balloon.body.body.linearVelocity.scaleEqual(0.92);
   balloon.body.body.angularVelocity.scaleEqual(0);
};



So now i want that my Player (balloon) move forward when i press W and change the rotation in one direction on press D .

var oKeyBoard = {
   fxKeyEvents: function (sKey) {
      if (sKey === 'd' && oKeyBoard.bPressRight) {
         balloon.rotate(BABYLON.Axis.Y, 0.1, BABYLON.Space.LOCAL);
      }
      if (sKey === 'w' && oKeyBoard.bPressRight) {
         var v = new BABYLON.Vector3(0, 0, 1);
         var m = balloon.getWorldMatrix();
         var v2 = BABYLON.Vector3.TransformCoordinates(v, m);
         v2.subtractInPlace(balloon.position);
         v2.scaleInPlace(1);
         balloon.applyImpulse(v2, balloon.position);
      }
   }
}


Press W works pretty well. The Balloon is going in the right direction and there is blocking by the yellow cube.
And when i now press D my Balloon will rotate in the right way, but if now press W again, the rotation of my ballon will be resetet to
his starting rotate values and "move" into the "old" direction.
i have now idea why and i hope that u understand whats my issue and u can help me ?! :)

The final goal is to create a controle like the good old Micro Machines games, with a bird perspective and WASD-controle... iam not sure that u know what i mean?! ^^

Fell free to ask me if you have any question.

Cheers
Arthuron

Link to comment
Share on other sites

Hi Arthuron, welcome to the forum!  I think I know exactly what you mean.

Let's take a look at the flying bed frame I made long ago.

http://urbanproductions.com/wingy/babylon/thruster/t26/flyer26.htm

Push/hold some buttons, or use control or shift number pad items...  rotate the flyer around to some weird angle.

Now press any of the position buttons.  The position thrust still aims perfectly along LOCALSPACE x/y/z.  By the way, all the thrusting of this flyer... is done on an invisible box that surrounds the flyer.  The thruster ports and particles are only there for coolness.  Its a box (flyerframe handle), using basic applyImpulse... or sort-of basic.

Now let's look at the "controller" file for the flyer.  http://urbanproductions.com/wingy/babylon/thruster/t26/js/controller08.js

In there, you will find THIS cool code, written for me by our local super-hero, Deltakosh:

//  a special func - thanks Deltakosh! :)

BABYLON.FlyerFrameController.prototype.doTransformPerFlyerQuat = function (vec) {
	var mymatrix = new BABYLON.Matrix();
	this.flyerframe.handle.rotationQuaternion.toRotationMatrix(mymatrix);
	return BABYLON.Vector3.TransformNormal(vec, mymatrix);
};

You can name it anything, of course.

Now let's look at 2 of the 8 positioning functions just above that.  Here's translate -x and translate +y funcs.

	BABYLON.FlyerFrameController.prototype.transNegativeX = function () {
		this.flyerframe.thrusters[7].start();
		this.flyerframe.thrusters[10].start();
		this.flyerframe.thrusters[13].start();
		this.flyerframe.thrusters[16].start();

		var forcevec = this.doTransformPerFlyerQuat(new BABYLON.Vector3(-this.transforce, 0, 0));
		var cntptvec = this.flyerframe.handle.position;
		this.flyerframe.handle.applyImpulse(forcevec, cntptvec);

	};
// --------------------------------------------------------------------------------------------------
	BABYLON.FlyerFrameController.prototype.transPositiveY = function () {
		this.flyerframe.thrusters[6].start();
		this.flyerframe.thrusters[12].start();
		this.flyerframe.thrusters[18].start();
		this.flyerframe.thrusters[24].start();

		var forcevec = this.doTransformPerFlyerQuat(new BABYLON.Vector3(0, this.transforce, 0));
		var cntptvec = this.flyerframe.handle.position;
		this.flyerframe.handle.applyImpulse(forcevec, cntptvec);
	};

Again, ignore the thrusters... they are there for "looks".  The real thrusting happens against flyerframe.handle, the invisible box around the flyer. 

this.transforce is the amount of impulse power.  Notice in the transNegativeX func,

var forcevec = this.doTransformPerFlyerQuat(new BABYLON.Vector3(-this.transforce, 0, 0));

A negative transforce is put into the X of the vector3 that gets sent to doTransformPerFlyerQuat.  Makes sense, because it is a negative X translation.

Now let's look at transPositiveY: 

var forcevec = this.doTransformPerFlyerQuat(new BABYLON.Vector3(0, this.transforce, 0));

A positive transforce is put into the Y of the vector3 that gets sent to doTransformPerFlyerQuat.  Makes sense, because it is a positive Y translation.

As you likely know, physics-active mesh and their physics body... use Quaternions to hold the rotation.  Physics bodies essentially ignore Vector3 Euler rotating.  When you applyImpulse to make a rotation (often requires two impulses, in opposite directions, at the same time, to get a nice non-skidding spin), the rotation values are stored in mesh.rotationQuaternion.  In Deltakosh's "transformer" func, you can see the rotationQuaternion of my flyer gizmo (flyerframe.handle)... being used.  The transform that is being done... is based-upon a matrix derived from the mesh.rotationQuaternion, and not from getting its worldMatrix.

You were SO CLOSE to having it perfect.  This function stopped my flyer dev for 3 months, and I never got as close to getting it correct... as you did. 

I think if you play around with Deltakosh's transformer a bit, it will work for you, too.  And feel free to use ANYTHING from my flyer (but it uses an OLD Babylon.js version, so it might be a bit stale).  Get the zip, here.  The whole controller08.js file... is full of keypress goodness and button-ready impulsing funcs.  You can drive that flyer with control and shift number pad, or control/shift keys surrounding ; key (for those with no numeric keypads).  I think shift/control page-up and page-down keys are involved with the latter, too.

And, I think... that you can get all the translations into a single func, and all the rotations into a single func, too, if wanted.  I kept them all separated into specialty funcs... just to make it easier for me to read my own code.  :)

Again, welcome!  I hope I understood your issue.  Example:  You want your right-side impulsing.... to happen on the right-side of the mesh, no matter how the mesh is rotated, correct?  Take some time to try some things with Deltakosh's transformer func... and keep us posted.  I hope it works for you, or at least gives you some new ideas.  Party on!

Link to comment
Share on other sites

Thank you very much for your fast answer @Wingnut
But i tried all day to understand this "magic function" and implemented in my code.

without success :unsure:
I hoped there exist an easy way and anyone says ---

"oh yes is realy simple dont use":
balloon.rotate(...);
"use bether this one":
balloon.magicPhysicRotate(...);

But i realy dont understand physics correctly at the moment.

My last try was to dispose my player mesh on as long you pressed the D key and recreate it, with the new (higher) rotaion value ... but this is to dirty :rolleyes:
iam sorry that iam so stupid to understand what you telling me ... do you think, it is bether for to start from the scratch and learning basics about physics?!

Link to comment
Share on other sites

No no, Authuron, you're not being stupid at all.  I misunderstood your issue.  Sorry about that.

Some of us were just recently talking about the need for a mesh.updatePhysicsBodyRotation() function in another topic thread. Interesting that you would need this, at this time.

8 hours ago, Arthuron said:

balloon.rotate(BABYLON.Axis.Y, 0.1, BABYLON.Space.LOCAL);

I didn't notice that part of your code.  Dummy me.

Yep, I think that might be called "trying to set the mesh.rotationQuaternion WHILE the physics body has control of rotation".  Maybe not allowed via normal/standard methods.  Your code is perfect for rotating a BabylonJS mesh via Quaternion, but without a mesh.updatePhysicsBodyRotation(), you have no way of getting those values transferred onto the physics body Quaternion.

As far as I know... AFTER mesh.setPhysicsState(), TWO Quaternions get involved.  Mesh has mesh.rotationQuaternion, and the physicsBody has a rotation/orientation Quaternion, too.  I suspect they are NOT the same Quaternion.  (As far as I know.)

Sooooooo.... hmm.  Let's 'assume'... that you need to do manual rotating of the physicsBody of your balloon.  You already know how to get balloon.body  (quite advanced for a new physics user, by the way.  Good job.)

Now let's pretend you are using Cannon.js as your physics engine of choice.  Let's go visit its API... http://schteppe.github.io/cannon.js/docs/

Now let's choose 'body' from the left sidebar there.  I'm thinking that's the API for the physics body.

Notice that there is a Quaternion on body.  Cooooool.  balloon.body.quaternion  Look out!  Let's click on the word Quaternion, to go look at CannonJS's Quaternion class.

Scroll down a bit, and we see cool methods like set, setFromAxisAngle, setFromEuler, setFromVectors... you might want to try some of those.  I have never tried rotating a physics body in this way... so if it blows up and your dog loses a tooth, I'm not responsible, ok?  You might be the first BJS user to ever try this... and we want to know how it turns-out, ok?  YOU could be the BabylonJS contributor/inventor for AbstractMesh.updatePhysicsBodyRotation, the sister to AbstractMesh.updatePhysicsBodyPosition.  You could be a BJS superstar!  Cooooool.

IF you are using Oimo.js instead... umm... we can look at a crappy API for it that I once collected.  Go here...  http://urbanproductions.com/wingy/babylon/misc/j2h02.htm

Search document for...  com.element.oimo.physics.dynamics.  Next to that... 'RigidBody' (body) label is seen.  Go down the list to item #9...  public var orientation:Quat;  (yay!)  balloon.body.orientation!  Look out!  Careful here.  In Oimo... it might be TWO 'body'... as in balloon.body.body.orientation.

Now search that same document... for com.element.oimo.math.  Once found, scroll down a ways... until you find Quat.  Look down through its poorly formatted list of methods, and we see not much "set" stuff.  But we DO see SOME stuff... especially item #3 - public function init(s:Number = 1, x:Number = 0, y:Number = 0, z:Number = 0)  hmm, you might be able to force some values into that.  Item 12.. 'copy' might be useful, too.  Maybe you can tell the physics body.body to copy mesh.rotationQuaternion.   *shrug*  The 's' value in the Oimo quat... COULD be the same as the 'w' value of a BabylonJS quat.  But maybe not.  They COULD be incompatible. Maybe using BJS quat values in an Oimo quat... will give bad results.  Not sure.

I hope I'm not on a wild goose chase.  Maybe none of this stuff will work.  Maybe it will.  Tell us what you discover, please.  You are the teacher, now.  :)  Welcome aboard! 

Link to comment
Share on other sites

On 2/5/2016 at 6:16 PM, Wingnut said:

As far as I know... AFTER mesh.setPhysicsState(), TWO Quaternions get involved.  Mesh has mesh.rotationQuaternion, and the physicsBody has a rotation/orientation Quaternion, too.  I suspect they are NOT the same Quaternion.  (As far as I know.)

So! you are totally correct on the first statement, and half correct on the second one. 

They are two quaternions, coming from two different systems. One is BabylonJS, the other is the physics engine we are currently using. What Babylon's phyiscs plugin does is constantly update the MESH's quaternion with the physics engine's BODY quaternion. and this is why, as you said, the quaternion change in BabylonJS won't affect the body at all.

There is a way around it, as you have already wrote - changing the mesh's quaternion and calling mesh.updatePhysicsBodyPosition(), which actually updates the body's rotation as well :) (if if it doesn'T work, please let me know). Maybe changing the name to updatePhysicsBodyTransformation() or something similar would be better. I'll consider this in my physics engine update for 2.4.

@Arthuron - I am sorry, but I didn't really understand your initial question. But a simple answer to your second one would be - use rotate, and update the physics body state (updatePhysicsBodyPosition) right after. this will rotate the  mesh in the physics engine too. But i am not entirely sure this is what you need.

Link to comment
Share on other sites

But but but but... umm... updatePhysicsBodyPosition only updates the rotation FROM mesh.rotationQuaternion, correct?  It will not update rotation from mesh.rotation.  (I think)

It WILL update physics body positions... from mesh.position.  See the inconsistency?  I think there is one there.

To update physicsBody rotation... from the values stored in mesh.rotation... umm... let's see.

1. var newQuat = new BABYLON.Quaternion.RotationAlphaBetaGamma(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);

   Get real, Wingy!  :)  var newQuat = mesh.rotation.toQuaternion();

2. myOimoBody.body.orientation.copy(newQuat);

http://www.babylonjs-playground.com/#RRUBU#4

A little broken testing scene.  :)  Lines 30-37 is my new UpdateROTATION func... where I attempt to set... well, you can see.

The box has a little Y-rotation happening (render loop).  NOP line 21 to see the spin.  Or... NOP line 49 to see the not-rotated-on-Y physics activity.

My updater fails, probably in line 36 where I try to do OimoQuat.copy(BjsQuat).  In line 35, I tried something demented.  BJS Quats have x, y, z, and w props.  Oimo Quats have s, x, y, and z props.  De-NOP line 35, and get some success!  SOMETHING got copied into the Oimo Quat, because our box starts rotating during the air-drop.  Unexpected axis, though. We were hoping for Y.  Box shows some X-rot.

I have SO MUCH to learn.  Thanks for looking-into other names/ideas, and for any thoughts on allowing users to use mesh.rotation as the source values for the rotation update on the physics body.  And thx for correcting my mistakes, Raanan!  I love it when folks do that.  Really.  Less foot taste in my mouth.  :D

Link to comment
Share on other sites

About the renaming...

   Maybe we WANT both updatePhysicsBodyPosition, AND updatePhysicsBodyRotation, and keep them separate?

   Maybe a separate updatePhysicsBodyScale, too?  Just thinkin'.

   UpdatePhysicsBodyImpostor?  UpdatePhysicsBodyParameters({mass: 0, friction: 0, restitution: .5});  ??  Goofy.  :)  I suppose those could be done... by doing another mesh.setPhysicsState(something different);  But doing that might null-out/reset some things, like velocities.  We would want to change impostors while maintaining energy... for maximum goofy-levels.

A good example... is my snow-plowing and snow-blowing game (still a dream).  It is going to take a LOT of little mesh to simulate snow plowing and road grading, but "Jerome's SPS poor-man's physics engine on a stick" is up to the task, in my opinion.  In order for artificial snow to roll-off-of the curved meshImpostor blades of a V-plow PROPERLY, it will need to be spheres and sphereImpostors.  Snowballs, essentially.

But, after the snow is XX distance from the plow blade, the snow balls could be told to LOD into being boxes or pyramids, and switch to boxImpostors.  This might speed-up the scene-wide physics updating speeds.  We would want to switch impostors, yet KEEP the current velocities, and keep mass/inertia/friction... from the original.  Generally, snow plowing is not a high-speed sport, so we caught a break, there.  :)

Pretend a sphere impostor is rolling across a plane, and then suddenly, it changes to a box impostor (yet still a sphere mesh).  Demented.  heh
  "Mom, Jimmy did something to my bowling ball and now it won't roll anymore!"

Ok, I'm off to snow-blow for an hour, in real life.  Seriously.  brrrrrr.  Thank goodness I have a space suit.

Link to comment
Share on other sites

Hmm good player.updatePhysicsBodyPosition(); works very fine.

but now is my next issue that i cant use my applyImpulse() together with my rotations?!
 

if (oKeyBoard.bPressLeft) {
  player.rotation.y -= 4;
  player.updatePhysicsBodyPosition();
}
if (oKeyBoard.bPressRight) {
  player.rotation.y += 4;
  player.updatePhysicsBodyPosition();
}
if (oKeyBoard.bPressUp) {
  var v = new BABYLON.Vector3(0, 0, 6.5);
  var m = player.getWorldMatrix();
  var v2 = BABYLON.Vector3.TransformCoordinates(v, m);
  v2.subtractInPlace(player.position);
  player.applyImpulse(v2, player.position);
}

aslong i rotate (press Left or Right in my case), the player.applyImpulse(...) doesnt run. Only i dont press a rotate button this code will run.
anyone an idea for that?

cheers

 

 

Link to comment
Share on other sites

Oh, sorry, Arthuron.  I wandered-off on tangents... screwing up your thread.

Any chance you could make a playground demo showing this issue, with a simple box as the player?

Anyway, regarding this code:

  player.rotation.y += 4;
  player.updatePhysicsBodyPosition();

I don't know if that rotation setting is getting set.  On the mesh, yes, it gets set.  On the physicsImpostor, I don't think so.

Try using something like... player.rotate(BABYLON.Axis.Y, 4.0, BABYLON.Space.Local);  (instead of player.rotation)

Keep us posted... and make that playground, eh?  :)  It will make it easier for folks to help.

Link to comment
Share on other sites

Ok ok ok ... i create a scene with my problem in a playground :D
http://babylonjs-playground.com/#2CRZWS#2
 

You can see my little white playerBox and the Big yellow one.
its possible to controle the playerBox by using WASD on your keyboard.
i want that my little playerBox cant move trough the big one, by this controles.

Notice:
i have removed my other functions and trys-solutions of my issues, to show simple where is my problem.

Hope its know bether understandable what i want. Sorry for my bad explanation :unsure:

Link to comment
Share on other sites

moveWithCollision is your friend! :)

No need for physics here. Here is your scene, with small modifications.

http://babylonjs-playground.com/#2CRZWS#3 

To do it with physics you will either need to change the physics body directly, or wait for BJS 2.4 where this functionality probably be integrated in the physics engine.

Link to comment
Share on other sites

I agree!  (like that matters)  :D

Speaking of changing the physics body directly, http://babylonjs-playground.com/#2CRZWS#4

Here, I'm using applyImpulse method to do just that.  You will see the "doTransformPerQuat" function in action (the magic func Deltakosh wrote for my flyer), and you'll see the two-impulse "twist" method that does the rotating.

The rotation isn't acting perfect.  Rotation seems to get "jammed" sometimes, and you need to give it a little forward/backward to get it to turn again.  Plus, when it DOES jam, the rotation impulses seem to get stored in a capacitor, and they discharge when you hit forward/backward again.  :)

I'm working on it.  :)

This method is not exactly good for a walking player, but for a drift-racing car, or spinning doughnuts on the local ice rink with your fried-out Combi, it works pretty well.  :)

Link to comment
Share on other sites

Oh now i see what you did @Wingnut , this is pretty amazing toooooo :wub:

absolute wonderful, know i must choose which solution ist the best for my tracks ingame ... i will try some expiremts with that.
For the Hero request ... Both, you and RaananW  ;)

Thanks so much for the fast competent help here !
Hope Jimmy and his bowling ball story will continue now :D

Link to comment
Share on other sites

http://urbanproductions.com/wingy/babylon/misc/info01.jpg

That picture applies to the #4 playground demo.  rotPower is the same as contactPoint offset rotPower is actually a distance.  When rotating left, for example:

line 88 - No matter how the player is currently rotated, I set my force vector to push the player toward the player's right.  +impulsePower is set in the X slot of the vector3.

line 89 - I move the contact point BEHIND (-z) player center.  I want to push +x direction, but at a contact point towards the BACK of the car/player.

line 90 - Impulse!  Push localSpace +x (but at a contact point towards the back of the mesh)  (localSpace +x means... car driver's right)

line 91 - Quickly move the contact point FORWARD-OF player center (+z)

line 92 - Reverse the force vector.  It was pushing +x.  Now it is pushing -x.

line 93 - Impulse!  Push localSpace -x (but at a contact point towards the front of the mesh)  (localSpace -x means car driver's left)

Twist!  You understood all this already, didn't you Arthuron?  *nod*

"C'mon baby... let's do The Twist", etc.  :)   BabylonJS fun!

Plus, we might be just getting started, here.  All of us could find new discoveries and have more ideas, yet.  The power of white-boarding in the playground... it never fails.  But the code I write with it... sometimes does.  heh

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...