A math problem with the rotation of a single ball.

Discussion about everything. New games, 3d math, development tips...
Post Reply
FrSl
Posts: 19
Joined: Thu Jan 19, 2006 5:03 pm

A math problem with the rotation of a single ball.

Post by FrSl »

Hello coders,

I'm working on a snooker game at this moment, but i've a mathematical problem now and i hope that someone can help me with this problem. The code is in Java irrlicht(Jirr) because i'm better in java, but i think that it's good understandable for someone with c experience.

What I have now: I can move a ball to a location, but I would also like some kind of roll effect of the ball. But that's not really working well at this moment, this is the code:

Code: Select all

ballOutline = (float)165,25; //2pi*r
speed = (float)15; //Speed of the ball 15pix/frame
angle = 0.2*Math.PI; //The angle the ball is heading

d_X = Math.sin(angle)*speed; //The translation of the x 
d_Z = Math.cos(angle)*speed; //The translation of the z 

rx = (float)360/(ballOutline/d_X); //rotation around x
ry = (float)0;
rz = (float)360/(ballOutline/d_Z); //rotation around z 

ball.setRotation(rx, ry, -rz)
With this method it's working well for a 90,180,270 or 360 angle. Because then there is only movement around 1 axis. But when I try with different angles then it looks very weird. :|

I've tried a lot of things allready, but I've no idea how to solve this problem.

Any help would be appriciated!
Baal Cadar
Posts: 377
Joined: Fri Oct 28, 2005 10:28 am
Contact:

Post by Baal Cadar »

Use quaternions instead of euler angles for this calculation. Much easier to handle. Quaternions represent rotations in angle/axis components and are thus better suited here.

First determine amount of angular velocity. Should be easy to calculate from circumference of a circle and the ball's linear velocity. This is if friction with table cloth is fully kicking in, less else. Scale the angular velocity with the time step to get the actual angle.

Then determine the axis of the rotation. This is the cross product of impact direction of the cue and the table normal.

Build a quaternion from current rotation of the scene node, then build a quaternion from the calculated angle/axis, multiply these two and convert the result to euler angles. Then apply the euler angle to the scene node.

See API docs for details.

Actual ball physics is much more complicated then this and hard to compute all by yourself. Consider using a physics library.
FrSl
Posts: 19
Joined: Thu Jan 19, 2006 5:03 pm

Post by FrSl »

Thanks for the help Baal Cadar!

It doesn't sound to hard, but it will take some time for me to find out how those matrixes work... :lol:

About the physic library, I don't think that i'll use 1 for this project, most of the calculations are allready done. (ball collision detection and table bouncing collisions are allready done.) But those ball rotations are not so easy. :?

EDIT: Hmm, looks like quaternions are not the same as matrix calculations. I hope so, i don't like matrix calculations :P
Baal Cadar
Posts: 377
Joined: Fri Oct 28, 2005 10:28 am
Contact:

Post by Baal Cadar »

Quaternions, not matrices. :)
Quaternions sound so extremely complicated, while they simply aren't. Don't worry about it.
Here is a useful primer on them and other rotation representations: http://www.ogre3d.org/wiki/index.php/Qu ... ion_Primer
While this is not Irrlicht, you can use them similiarly in Irrlicht. All used quaternion functions are in some form or another available in Irrlicht too.
FrSl
Posts: 19
Joined: Thu Jan 19, 2006 5:03 pm

Post by FrSl »

Great help Baal Cadar!

The wiki page looks very useful, I'll read it to understand those quaternions. :)
FrSl
Posts: 19
Joined: Thu Jan 19, 2006 5:03 pm

Post by FrSl »

Hello, i understand the things of the wiki and also understand you're story but i can't get it working in irrlicht :roll:

So, i hope you can help me out 1 more time :P

My idea was to create a 'simple'(not for me) rotation first. A 45deg degree movement to the left. I made 2 pictures to explain the values i picked:

Image

I used 2 quaternions like you said and filled them like this:

Code: Select all

        //This code will be used every frame for the ball rotation
        vector3df currentRotation = ball[k].node.getRotation();

        vector3df myaxis = new vector3df((float)0.75, 0, (float)0.75); // the red arrow
        float myangle = (float)(0.1*Math.PI); // very small rotation around the myaxis every frame
        vector3df myrotation = new vector3df((float)0.5, 0, (float)0.5); // the blue arrow
        quaternion a = new quaternion(); //1 for the axis
        quaternion b = new quaternion(); //1 for the rotation

        //first way:
        //a.fromAngleAxis(myangle, myaxis); //fill a                       
        //b.toEuler(myrotation); //fill b                     
        //or:                                       
        a.set(myangle, myaxis.getX(), myaxis.getY(), myaxis.getZ()); //fill a               
        b.set(myrotation.getX(), myrotation.getY(), myrotation.getZ()); //fill b                   

        a.getDotProduct(b); //a*=b

        //set the rotation
        ball[k].node.setRotation(new vector3df(currentRotation.getX() + a.getX(), currentRotation.getY() + a.getY(), currentRotation.getZ() + a.getZ()));  
But the rotation is very strange, it's not moving around but more like spinning on 1 side of the ball.

I hope you can help me out with this example, if i've 1 working example then the rest won't be so hard anymore(i hope :))
Baal Cadar
Posts: 377
Joined: Fri Oct 28, 2005 10:28 am
Contact:

Post by Baal Cadar »

Never set wxyz components of quaternion yourself, unless you know how they work internally (which you don't need to, to work with them)
The way you use the set-function is wrong. I also don't understand the dot product. What is the intention? You don't do anything with the result anyway.

This code is untested, but should work.

Code: Select all

// Get the balls current rotation and convert it to a quaternion
vector3df euler = node->getRotation();
quaternion current(euler.X, euler.Y, euler.Z);

// Create the rotation to be applied from the angle/axis
// IMPORTANT: Axis has to be normalised.
vector3df axis = vector3df(0.75f, 0.0f, 0.75f);
axis.normalize();
quaternion rotation;
rotation.fromAngleAxis(0.1*Math.PI, axis);

// Apply the new ortation to the current orientation
// Not sure here, might be rotation = current * rotation;
// Quaternion mulitplication is not commutative
rotation = rotation * current;

// convert to euler angles and apply result to node
rotation.toEuler(euler);
node->setRotation(euler);

FrSl
Posts: 19
Joined: Thu Jan 19, 2006 5:03 pm

Post by FrSl »

I also don't understand the dot product. What is the intention?
In java the * operator is not working for quaternions that's why i used the getDotProduct function;

---

But I'm sorry, but i still can't get it working :oops:

I changed the HelloWorld tutorial a bit to make the code small and easy to read. But the ball is just moving a little but no real rotation. I really tried everything, changed every value to get a better rotation, tried to switch rotation = rotation * current; to rotation = current * rotation; without effect. I've no idea anymore, in you're example it looks good to understand but I can't get it working the way it should be. :oops:

I've uploaded a zip with the c file, exe, model and irrlicht.dll in it:
http://www.yourfilelink.com/get.php?fid=79362

This is my complete test file: (switched back from java to c to test this)

Code: Select all

#include <irrlicht.h>

using namespace irr;

using namespace core;
using namespace scene;
using namespace video;
using namespace io;

#pragma comment(lib, "Irrlicht.lib")

int main()
{
    //Setup irrlicht
	IrrlichtDevice *device = createDevice(EDT_SOFTWARE, dimension2d<s32>(640, 480), 16, false, false, false, 0);
	IVideoDriver* driver = device->getVideoDriver();
	ISceneManager* smgr = device->getSceneManager();
	smgr->addCameraSceneNode(0, vector3df(0,10,-100), vector3df(0,5,0));
	
    //Load the model
    device->getFileSystem()->addZipFileArchive("Ball2.zip");  
    IAnimatedMesh* mesh = smgr->getMesh("Ball2.3DS");
    ISceneNode* node = smgr->addOctTreeSceneNode(mesh->getMesh(0));
    node->setPosition( core::vector3df(0,0,0) );            
    
	while(device->run())
	{
        // Get the balls current rotation and convert it to a quaternion
        vector3df euler = node->getRotation();
        quaternion current(euler.X, euler.Y, euler.Z);
        
        // Create the rotation to be applied from the angle/axis
        // IMPORTANT: Axis has to be normalised.
        vector3df axis = vector3df(0.75f, 0.0f, 0.75f);
        axis.normalize();
        quaternion rotation;
        rotation.fromAngleAxis(0.1f * 3.14f, axis);
        
        // Apply the new ortation to the current orientation
        // Not sure here, might be rotation = current * rotation;
        // Quaternion mulitplication is not commutative
        rotation = rotation * current;
        
        // convert to euler angles and apply result to node
        rotation.toEuler(euler);
        node->setRotation(euler);                         
                        
		driver->beginScene(true, true, SColor(255,100,101,140));
		smgr->drawAll();
		driver->endScene();
	}

	device->drop();
	return 0;
}
I hope you could take some time to look at the code for one more time, i will be very happy if the example should work normally. :roll:
Skip Talbot
Posts: 2
Joined: Sun May 07, 2006 4:18 pm
Location: Illinois
Contact:

Post by Skip Talbot »

I know this thread has been here awhile, but I wanted to post a slight correction for the next person who stumbles upon a similar problem.

Code: Select all

// Get the balls current rotation and convert it to a quaternion
vector3df euler = node->getRotation();
quaternion current(euler.X, euler.Y, euler.Z);

// Create the rotation to be applied from the angle/axis
// IMPORTANT: Axis has to be normalised.
vector3df axis = vector3df(0.75f, 0.0f, 0.75f);
axis.normalize();
quaternion rotation;
rotation.fromAngleAxis(0.1*Math.PI, axis);

// Apply the new ortation to the current orientation
// Not sure here, might be rotation = current * rotation;
// Quaternion mulitplication is not commutative
rotation = rotation * current;

// convert to euler angles and apply result to node
rotation.toEuler(euler);
node->setRotation(euler); 
The toEuler function of the quaternion class produces radians, and setRotation takes degrees, so you need to multiply by 57.2957795...

Code: Select all

rotation.toEuler(euler);
node->setRotation(euler*57.2957795); 
Skip Talbot
Skip's Webzone
Post Reply