Sorry for the long response time, but I had some other assignments to take care of.
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).
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):
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
for (unsigned int k = 0; k < arrows.size(); k++)
anArrow = arrows[k];
direction = anArrow->getLinearVelocity();
rotation = anArrow->getOrientation();
difference = getQuaternionByVector(direction) - rotation;
Where getQuaternionByVector gives you the direction of a 3D vector as a quaternion
btQuaternion getQuaternionByVector(btVector3 vDirection)
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.
//(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)...
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.