[Give the normal of a surface in XYZ format, how do I calculate rotations (also in XYZ format) needed to set an object parallel to the surface?]
I have a collision library that uses the bullet physics library to detect collision points of ray-casts. It all works well as it is, but I want to add more to it. I want to get angles of the endpoint that can be used to "lay" an object onto a surface.
Here's everything I have and want.
First, here is my pizza: Imgur
Second, a light house in a full view: Imgur
Last, how I want to cast the ray (let the red line be the ray): Imgur
I want to be able to set the pizza's angles (in XYZ, axis's shown above) so that the pizza lays on the roof of the light house using the rotation information (normal) retrieved from bullet's ray-cast.
This may seem like a programming question, but you don't have to have a programming answer. Just tell be how to get the math right for RX, RY, and RZ and I can implement the code.
The following code works, but only if the raycast is straight down.
Here is what I'm currently using, but it is not correct in most cases.
//Header file
const btScalar RADIAN_TO_DEG = btScalar(57.29577951);
//Function
btVector3 Rotation = RayCallback.m_hitNormalWorld;
RX = -(asin(Rotation.getY())RADIAN_TO_DEG);
RY = asin(Rotation.getX())RADIAN_TO_DEG;
RZ = 0.0;
RX, RY, and RZ are going to be the pizza's angles. If you are not a programmer you'll probably want to know what the Rotation is. The Rotation = line stores the normal of the surface that was 'hit' in radian. Then the asin of the normal's X and Y is converted to degrees and stored to RX and RY.
Full code for the plain ray-cast function that returns the first collision:
int ColAndreasWorld::performRayTest(const btVector3& Start, const btVector3& End, btVector3& Result, uint16_t& model)
{
btCollisionWorld::ClosestRayResultCallback RayCallback(Start, End);
dynamicsWorld->rayTest(Start, End, RayCallback);
if (RayCallback.hasHit())
{
Result = RayCallback.m_hitPointWorld;
model = RayCallback.m_collisionObject->getUserIndex();
return 1;
}
return 0;
}
Full code for the new ray-cast function that returns the first collision and angles for the object:
int ColAndreasWorld::performRayTestAngle(const btVector3& Start, const btVector3& End, btVector3& Result, btScalar& RX, btScalar& RY, btScalar& RZ, uint16_t& model)
{
btCollisionWorld::ClosestRayResultCallback RayCallback(Start, End);
dynamicsWorld->rayTest(Start, End, RayCallback);
if (RayCallback.hasHit())
{
btVector3 Rotation = RayCallback.m_hitNormalWorld;
RX = -(asin(Rotation.getY())*RADIAN_TO_DEG);
RY = asin(Rotation.getX())*RADIAN_TO_DEG;
RZ = 0.0;
Result = RayCallback.m_hitPointWorld;
model = RayCallback.m_collisionObject->getUserIndex();
return 1;
}
return 0;
}
Ps. I'm new here, sorry if this is a horrible explanation/question. Also, if you're wondering why the Y axis rotation is negated, it's because the game's is just weird like that. The Y axis is inverted in the game.


