1

[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

enter image description here

Second, a light house in a full view: Imgur

enter image description here

Last, how I want to cast the ray (let the red line be the ray): Imgur

enter image description here

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.

  • So... you want to rotate the pizza so that its $z$ axis lies along the surface normal, is that right? –  Jul 27 '15 at 18:24
  • Well, yeah. All of the axes need to be rotated. – Corey Iles Jul 27 '15 at 18:39
  • Aren't the axes of the pizza underdetermined? You can spin it on the roof around the pizza's (rotated) $z$-axis so that it remains lying on the roof, right? IOW there are infinitely many ways to pick the direction of pizza's $x$-axis while keeping its $z$-axis normal to the roof. The $y$-axis is then determined by the right handed rule. Yet in other words: in addition to just pepperoni you need to place a single olive on the pizza (not in the center!), and declare that the $x$-axis goes through the olive. And then you need to specify where the olive direction is on the roof. – Jyrki Lahtonen Jul 27 '15 at 19:21
  • Good point. The pizza may've been a bad example since it is circle. No matter what it's Z angle is, as long as it's X and Y are correct it will still lie on the roof. That's where my main problem is, X and Y. My current method is only correct when the ray is straight down. I want to be able to cast a ray any direction and get the correct angles from the normal. For example, in the picture with the red ray cast toward the roof; the angles returned will have the pizza half way in the roof because the X and Y are wrong. If the ray was straight down the angles would be correct. – Corey Iles Jul 27 '15 at 19:51
  • PS. I just discovered that even casting straight down can return bad angles. – Corey Iles Jul 27 '15 at 20:01
  • Is this for a breaking bad video game? https://www.youtube.com/watch?v=RKAzfd8oTWs – rajb245 Jul 27 '15 at 20:04
  • @rajb245 Well that's quite off topic for one, and for two the pizza and roof thing was just an example. It's actually for a GTA:SA mode called SA:MP. – Corey Iles Jul 27 '15 at 20:05
  • I forgot to tag @JyrkiLahtonen – Corey Iles Jul 27 '15 at 20:10
  • Does this previous post answer your question? –  Jul 28 '15 at 00:56
  • @Rahul What the OP is asking for sounds right, but how do I get the X, Y, and Z rotations from the answer there? I'm not absolutely sure how to convert all of that to X, Y, and Z. I need the pizza to be parallel to the surface that the ray collided given the normal of the surface collided. – Corey Iles Jul 28 '15 at 01:32
  • Update: Let {-0.7553, -0.4568, 0.4698} be the normal of a face. The rotations I need would be {-20.0000, 60.0000, 0.0000}. Unfortunately, my code above returns {27.1840, -49.0530, 0.0000}. – Corey Iles Jul 28 '15 at 02:38
  • Unity's Quaternion.FromToRotation is what I need. Unfortunately I can't find the source for it anywhere (obviously), does anyone know how they do it? – Corey Iles Aug 10 '15 at 22:29

0 Answers0