Arrow flight modeling

Post Reply
eltorre
Posts: 2
Joined: Thu Mar 22, 2012 6:01 pm

Arrow flight modeling

Post by eltorre »

I am trying to model a realistic arrow flight path, but i dont know how to. I get the parabolic path (it is easier than I though), but the arrow does not rotate. In real world, an arrow points (or tries to point) in the direction of its linear velocity vector.

I am using this code for creating the arrow

Code: Select all

void shootArrow(double px, double py, double pz, double dx, double dy, double dz, double m)
{
	btCylinderShape *capsule = new btCylinderShape(btVector3(0,0.5,0)); //In the start it was a capsule, not a cylinder
	btScalar mass(m);
	btVector3 localInertia(0,0,0);	//I don't know what values to give.
	capsule->calculateLocalInertia(mass,localInertia);
	btTransform startTransform;
	startTransform.setIdentity();
	startTransform.setOrigin(btVector3(px,py,pz));

	//getDifference returns a quaternion that represents the difference between both vectors.
	// It works well. Arrows point same way as the initial linear velocity vector (dx, dy, dz).
	startTransform.setRotation(getDifference(btVector3(dx, dy, dz), btVector3(0, 1, 0)));	
	
	btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
	btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,capsule,localInertia);
	btRigidBody* body = new btRigidBody(rbInfo);
	body->setLinearVelocity(btVector3(dx, dy, dz));

	m_dynamicsWorld->addRigidBody(body);
	arrows.push_back(body);
}
I thought it should work like this, but it does not, because the cylinder has the center of mass in the exact middle, and no force applies (besides the gravity, witch affects the full shape in the same direction).

I have tried to move the center of mass, but it does nothing, bullet cant have a center of mass that is not the center of the shape (at least that is what i read in the wiki).

I tried to use applyTorque, but i do not know how to use the function. I thought getting the difference between orientation of the shape and the linear velocity vector in axis-angle format should work, but it does not (or I did something bad...).

I just have one idea left: to use a fixed constraint to hold a body with weight but no shape (no collisions) to the tail of the arrow. But it feels bad, bullet does not provide fixed constraints, and i think there should be a good reason for that.

Somebody tried this before and can share a tip or two?
spiderworm
Posts: 2
Joined: Thu Mar 22, 2012 3:26 pm

Re: Arrow flight modeling

Post by spiderworm »

I can't say that I've tried it before, but in the project I'm working on, I will be doing this at some point. I for one am in favor of having two physics objects constrained together, one for the arrowhead and the other for the shaft and tailfeathers. I don't see anything wrong with that, and it should work (based on my admittedly low current level of understanding).
alex-weej
Posts: 7
Joined: Thu Mar 01, 2012 10:07 pm

Re: Arrow flight modeling

Post by alex-weej »

At a guess, air resistance is what keeps the arrow pointing in the direction of flight, given a massive arrowhead. So modelling a torque on the object based on its velocity vector may be a good place to start. Let us know how you get on!
CookieMonster
Posts: 49
Joined: Sun Jan 29, 2012 10:01 pm

Re: Arrow flight modeling

Post by CookieMonster »

I would just make a sphere for the head and let the visual model do the aiming and rotation.
mi076
Posts: 144
Joined: Fri Aug 01, 2008 6:36 am
Location: Bonn, Germany

Re: Arrow flight modeling

Post by mi076 »

Code: Select all

btCylinderShape *capsule = new btCylinderShape(btVector3(0,0.5,0));
you have to give the bounding box values for cylinder shape, no zeros here...
I have tried to move the center of mass, but it does nothing, bullet cant have a center of mass that is not the center of the shape (at least that is what i read in the wiki).
of course you can move center of mass... take compound shape and add cylinder shape as a child

the idea (play with values, i didn't test them):

Code: Select all

        btCompoundShape * compound = new btCompoundShape();
        btTransform local_trans;
        local_trans.setIdentity();
        local_trans.setOrigin(btVector3(0.0f, 0.4f, 0.0f);
        //local_trans shifts the center of mass

        btCylinderShape * shape = new btCylinderShape(btVector3(0.05f,0.5f,0.05f));
        compound->addChildShape(local_trans,shape);

        btTransform trans;
        btQuaternion q(axis, rotation);
        trans.setIdentity();
        trans.setOrigin(origin);
        trans.setRotation(q);
        btVector3 local_inertia(0.0f,0.0f,0.0f);
        compound->calculateLocalInertia(mass, local_inertia);
        btDefaultMotionState * motion_state = new btDefaultMotionState(trans);
        btRigidBody::btRigidBodyConstructionInfo rbi(mass,motion_state,compound,local_inertia);
        btRigidBody * body = new btRigidBody(rbi);
eltorre
Posts: 2
Joined: Thu Mar 22, 2012 6:01 pm

Re: Arrow flight modeling

Post by eltorre »

Sorry for the long response time, but I had some other assignments to take care of.
mi076 wrote:

Code: Select all

btCylinderShape *capsule = new btCylinderShape(btVector3(0,0.5,0));
you have to give the bounding box values for cylinder shape, no zeros here...
I wanted a very thin cylinder, so i gave it 0 units of radius (0 in both x and z axes). It works bad when in continuous simulation (they slip through the floor, a btTriangleMesh), but I manually stop the arrows in the first collision, so it does not matter. They collide correctly with the test items (walls made of btConvexHullShapes and spheres).
mi076 wrote:
I have tried to move the center of mass, but it does nothing, bullet cant have a center of mass that is not the center of the shape (at least that is what i read in the wiki).
of course you can move center of mass... take compound shape and add cylinder shape as a child

the idea (play with values, i didn't test them):

Code: Select all

...
Shifting the center of mass makes no effect in the flight of the arrows, but when they collide with object, they are clearly being affected by this shift. I think the problem is the same as the starting one: the gravity affects the full object, not the center of mass, so no torque or angular velocity is applied because of gravity. Modifying the mass of the arrow does nothing (other than being "stronger" against other mobile objects).



After trying this, I implemented the torque idea. It gets the difference between orientation and linear velocity direction as a quaternion, and then applies it as a torque.

It has a big flaw: when the arrow is getting closer to the 0 torque zone (when orientation ~= linear velocity direction), the arrow still has angular velocity, so it overturns the arrow. Then, a torque of inverse direction starts to apply, so the arrow oscillates like a pendulum.

This only applies to arrows launched with a high angle, because of the sudden change of linear velocity direction in the zenith (it goes from near directly +Y to near directly -Y). The arrows launched with smaller angles (<60º) behave correctly, because there are no sudden changes.

This is the code I used to implement this

Code: Select all

	for (unsigned int k = 0; k < arrows.size(); k++)
	{
		btVector3 direction;
		btQuaternion rotation;
		btQuaternion difference;
		anArrow = arrows[k];
			
		direction = anArrow->getLinearVelocity();
		rotation = anArrow->getOrientation();
		
		difference = getQuaternionByVector(direction) - rotation;
		
		anArrow->applyTorque(-2*difference.getAxis());
	}
Where getQuaternionByVector gives you the direction of a 3D vector as a quaternion

Code: Select all

btQuaternion getQuaternionByVector(btVector3 vDirection)
{
    btQuaternion q;
    vDirection = vDirection.normalize();
    
    btVector3 vUp(0, 1.0f, 0.0f);
    btVector3 vRight = vUp.cross(vDirection);
    vUp = vDirection.cross(vRight); 
	

    q.setW(sqrt(1 + vRight.getX() + vUp.getY() + vDirection.getZ()) / 2.0);
    double dfWScale = q.getW() * 4.0;
	
    q.setX((vDirection.getY() - vUp.getZ())/dfWScale);
    q.setY((vRight.getZ() - vDirection.getX())/dfWScale);
    q.setZ((vUp.getX() - vRight.getY())/dfWScale); //Edit: values where mixed. 
	
    return q.normalize();
}       

//(This piece of code is based on the code snippet posted by acid1789 in http://forums.create.msdn.com/forums/t/5385.aspx
If anybody has another suggestion, I like to hear it. If nothing comes up, I think this will do the trick with some hard-coded condition, like setting the angular velocity to 0 when orientation ~= linear velocity direction (when the w component of the quaternion is nearly 0?). I do not like hard-coded conditions, and less when it affects a module I did not program (like bullet)...

Edit:

My maths only work on 0-width cylinders, and I do not know why.

Also, there was a little typo in the quaternion-making function that gave little problems with certain angles.
Post Reply