Thread: Defining a plane using three points?

  1. #1
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607

    Defining a plane using three points?

    This adds to another thread but is for a different reason thus another thread.

    Given this:
    http://www.peachpit.com/articles/art...02090&seqNum=3

    And this:
    http://mathworld.wolfram.com/Plane.html

    I'm afraid I do not understand this statement from the first link:

    Notice how we are defining the plane by three passing points. Thus, the plane is vertical, and its normal is pointing to the left side of the world, as seen from the local player position.
    Since the general equation of a plane is:

    ax+by+cz+d=0 or ax+by+cz=d (whichever you choose)

    And the constructor options for D3DXPLANE are:
    Code:
    D3DXPLANE() {}
    D3DXPLANE( CONST FLOAT* );
    D3DXPLANE( CONST D3DXFLOAT16* );
    D3DXPLANE( FLOAT a, FLOAT b, FLOAT c, FLOAT d );
    How do I construct a plane with only 3 points? Where is d?


    EDIT:

    I found the answer. Sorry.
    Code:
    D3DXPLANE * D3DXPlaneFromPoints(
      D3DXPLANE * pOut,
      CONST D3DXVECTOR3 * pV1,
      CONST D3DXVECTOR3 * pV2,
      CONST D3DXVECTOR3 * pV3
    );
    I'm going to use this to allow the AI space ships to follow waypoints, targets, and the player during battles. The code finds out which quadrant the target object is in and adjusts pitch and yaw respectively. I was going to use vector LERP but I have not converted to quaternions and using Euler's is such a PITA.

    I'm using vector LERP for auto-pilot tracking and target tracking using:
    Code:
    void VectorLERP(D3DXVECTOR3 &result,D3DXVECTOR3 v1,D3DXVECTOR3 v2,float lerp)
    {
       result.x=v1.x+lerp*(v2.x-v1.x);
       result.y=v1.y+lerp*(v2.y-v1.y);
       result.z=v1.z+lerp*(v2.z-v1.z);
    }
    Last edited by VirtualAce; 07-16-2007 at 01:46 AM.

  2. #2
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    In case you care about the maths, it works like this: Remember that in ax + by + cz + d = 0, a, b and c are the three components of the normal vector of the plane, while d is -N*P0 - that's the dot product of the normal vector with the point on the plane. In other words, this formula represents the plane as represented by a point and a normal.

    To get from three points to this representation, you choose any of the three points p1, p2 and p3 to be your p0. Then you need to compute the normal. For this, you calculate v2 and v3 as the vectors from p1 to p2 and p3, respectively. Then, you do a cross product on these two to get the normal.

    Finally, you just fill in the values.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  3. #3

    Join Date
    May 2005
    Posts
    1,042
    d is the dotproduct between the normal and a point on the plane (doesn't matter which point, they will all give the same value), some define it as the negative dotproduct between the normal and the plane (as does directx, which is a less intuitive approach, such that you add the d term rather than subtract it).

    To steer a spacecraft (simply just changing the orientation) is pretty simple, and you can do it with euler without having to switch to quaternions. You have two normalized vectors, A) one is the forward vector of the spacecraft, the other B) is the vector connecting where you want to turn to with the center of the spacecraft (WhatIWantToLookAt - SpaceCraft.GetPosition()).

    Take the crossproduct of these two vectors to get the axis of rotation (A x B). You can use this in either Euler or quaterions to easily turn towards a target, then move towards that target.
    Last edited by BobMcGee123; 07-16-2007 at 01:03 PM.
    I'm not immature, I'm refined in the opposite direction.

  4. #4
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Thanks all for the responses.

    I did exactly what you said Bob partly from other sites and partly from just figuring it out myself from my knowledge of vector operations.

    Big problem. It seems that Euler orientations are not unique. In other words if my spaceship is point at a planet and my yaw and pitch are 0.0f and 0.0f that orientation is not unique. It is possible to yaw and pitch all over the place and point back at the planet...and the yaw and pitch are not 0.0f 0.0f. But the formula I'm using always calculates the yaw and pitch to be 0.0f.

    Here is what I'm doing:

    Code:
    void CCamera::RotateTo(D3DXVECTOR3 vecTarget)
    {
      //vecTarget must share origin with camera vector
      D3DXVECTOR3 toTarget=vecTarget-Pos;
      D3DXVec3Normalize(&toTarget,&toTarget);
      
      //Normalize camera look
      D3DXVECTOR3 nLook;
      D3DXVec3Normalize(&nLook,&Look);
      
      //Cross product is axis of rotation
      D3DXVec3Cross(&m_vecAxis,&toTarget,&nLook);
      
      //Dot product is cos of angle of rotation
      m_fAxisAngle=D3DXVec3Dot(&toTarget,&nLook);
        
      //Construct axis angle rotation matrix
      D3DXMATRIX T;
      D3DXMatrixRotationAxis(&T,&m_vecAxis,m_fAxisAngle);
      
      //Now extract yaw, pitch, roll from T and rotate
      YPRFromRotMatrix(T,m_vecTargYPR.x,m_vecTargYPR.y,m_vecTargYPR.z);
      
      //Find difference between current YPR and new YPR to face object
      D3DXVECTOR3 diff;
      diff.x=m_vecTargYPR.x-m_fYaw;
      diff.y=m_vecTargYPR.y-m_fPitch;
      diff.z=0.0f;  
      m_vecRotInc=diff;
       
      //Test code to 'snap' to new orientation
      //Yaw(m_vecTargYPR.x-m_fYaw);
      //Pitch(m_vecTargYPR.y-m_fPitch);
      
          
    }
    So you see I'm doing exactly what everyone has shown. My problem is this. How do I transform my up,look, and right vectors to represent the new rotation? If the up, right, and look vectors are not altered in my camera class there is no rotation. I can create a matrix to do the rotation but I'm not sure what to do then?

    Code:
    D3DXVec3TransformCoord(&Up,&Up,&NewMatrix);
    D3DXVec3TransformCoord(&Look,&Look,&NewMatrix);
    D3DXVec3TransformCoord(&Right,&Right,&NewMatrix);
    Since I'm not sure this works what I did was create the new axis-angle rotation matrix and then proceed to extract the yaw and pitch from the matrix. Roll is pretty much a moot point in this so I don't use it.

    Using this the spacecraft does not always point at the same place. So when I want to turn to 0.0f,0.0f,0.0f it should be the same exact spot on the skysphere. It's not and often times it's way off.

  5. #5
    Registered User
    Join Date
    Apr 2006
    Posts
    43
    The yaw and pitch values should be some multiple of PI. Use mod, (angle % PI), before comparing them with zero. Observe that 180 degree yaw and 180 degree pitch is the same os 0 degree yaw and 0 degree pitch, only difference is that the roll angle is flipped.

    also observe that you need to apply yaw, pitch, roll transforms in the same order in your code to get consistent results.

    Don't you want roll angle too, since it's a space simulator and not just a ground based 3d game where up is always up?

    Be wary of taking code snippets from sites that talk about FPS, since Euler angles works fine as long as you don't look at the same direction as the up-vector (if you play Quake and look straight up/down I guess you'll see the screen start to spin, and you don't want that in a flight simulator). This has to do with the fixed up-vector, you need to have a matrix that describes the orientation of the camera so you can get your up-vector perpendicular with the look-at vector.

    I think you'll be much happier if you change to using quaternions, you will get much cleaner code that way in the end (and it's not difficult if you are comfortable with matrices and vectors to begin with).

    Yaw, pitch and roll is nice to use as input parameters but they suck when you use them between calculations (Euler angles contain singularities at the poles where the math breaks down). Though it is possible to do camera motion using Euler angles (I once did) but it's no fun.

    Look for code for generating a rotation matrix for rotating one vector to another. Then multiply the current camera orientation matrix with that rotation matrix and you should get the matrix that describes the new orientation. Order of matrix multiplies matter, it's not like scalar math.

    enough of my ranting...good luck =)

    /f

  6. #6
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I did not provide the entire camera class which does check roll, pitch, yaw, etc.

    The camera class works fine as is but the RotateTo() function does not work correctly. Crossing the vectors gets the axis and dotting them gets the angle. However applying this rotation to the up, right, and look vectors is problematic.

  7. #7
    Registered User
    Join Date
    Apr 2006
    Posts
    43
    How do you use m_vecRotInc?
    The calculations that you do seems ok, so I think it's the step after that that is messed up.
    What is in NewMatrix? Is that the delta rotation?

    How do I transform my up,look, and right vectors to represent the new rotation?
    You should multiply them with that rotation matrix...but it sounds like you're trying to do that though.
    Do you try to interpolate the transition in many steps or do you change the view direction in one go?

    Using this the spacecraft does not always point at the same place.
    Can you give an example of how you do when it doesn't point at the same place?
    Where and how do you apply the rotation to the view/camera matrix?

  8. #8

    Join Date
    May 2005
    Posts
    1,042
    As your vectors are normalized already, the angle is the acos of the dotproduct. That's the first problem I see (rechecking your code).

    Code:
      //Dot product is cos of angle of rotation
      m_fAxisAngle=acosf(D3DXVec3Dot(&toTarget,&nLook));
    Try that change and see if victory has been obtained.

    EDIT:
    How do I transform my up,look, and right vectors to represent the new rotation?
    Multiply by 'T'? (the matrix from D3DAxisAngleMatrix function or whatever). I'm a little confused why you make the axis-angle matrix only to then transform that to euler angles.

    I think that even when the math is correct you're still going to be wishing that you had never used euler angles. In my experience they are always going to be snapped from -PI/2 to +PI/2, and that when you go over that boundary there is a problem with signs which fusks up the delta angle (the difference between the angle you wish to be at and the angle you are currently at, because over the PI/2 boundary you get a sign change). Everything else will still work, but when you get to that boundary the angle will jiggle and act silly over the 90 degree marks. For example, think about implementing a camera where the actual camera view lags slightly behind the orientation of the spaceship, using purely the difference between euler angles (the biggest the difference, the faster the actual camera view tries to catch up towards the spaceship's view).
    Last edited by BobMcGee123; 07-17-2007 at 03:18 PM.
    I'm not immature, I'm refined in the opposite direction.

  9. #9
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I tried to multiply by T but it still did not work right. The only problem I can see is that my look vector is not pointing to the correct position after the rotation. This is the only problem that could cause incorrect rotations given my formula and other math is correct. So if the look vector is not correctly being transformed then the cross product is incorrect and thus the dot product also incorrect.

    Every time I press "A" (autopilot) the view changes but to a totally different orientation. And yes I have experienced the angle jiggling. I don't really need the yaw, pitch and roll and the camera class does not depend on them.

    I will work some more on it tonight and post my results. This is key to getting my navigation, targeting, and auto pilot systems working.

    After this I need to work on another important part of the AI system which is predictive targeting. It would be nice to have a predictive target cursor as well so the player can fire at this and know if he is somewhere close to this area he has a very good chance at hitting the target.

    I'm assuming this is a simple operation in which you extend the velocity vector out from the target a distance which is determined by target speed and the time it will take for the laser to reach that point. I could even forget the laser travel time to the target since it's very fast and probably would not make much of a difference.


    EDIT:

    It's fixed. Since this is for the camera class I had to negate the dot product and also negate the vector I wanted to point to. So if I wanted to point at 1000,1000,1000 I would say rotateTo(-1000,-1000,1000) and it works. I'm assuming that for a vehicle the formula would work fine by using the non-negated dot product and non-negated vector. To correct this I subtracted the position of the camera from the position to look at, instead of the position to look at from the camera position. But I still need to use the negated dot product for this to work. This makes sense since in the D3DXMatrixLookAtLH docs it shows the matrix uses the negated dot product between the axis and the eye point in the bottom row.

    Thanks all for the help. Now I guess all that's left is to do a LERP from the current camera's orientation to the new camera's orientation. I will use right, up, and look for this and do a lerp from the current right, up, and look to the newly compute right, up, and look. I really am not using Euler angles in my system. My system orients objects using right, up, and look and performs axis angle rotations for yaw, pitch, and roll or for x,y and z rotations.
    Last edited by VirtualAce; 07-18-2007 at 12:19 AM.

  10. #10

    Join Date
    May 2005
    Posts
    1,042
    Did you correct the error with improperly computing the fAxisAngle value?
    I'm not immature, I'm refined in the opposite direction.

  11. #11
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Yes I did. My original code had the acosf() so I'm not sure what happened in my post.

    Thanks all for the help.

  12. #12
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Final working code for anyone that is interested in implementing something similar.
    Code:
    void CCamera::RotateTo(D3DXVECTOR3 vecTarget)
    {
      //vecTarget must share origin with camera vector
      D3DXVec3Normalize(&m_vecTarget,&vecTarget);
       
      D3DXVECTOR3 nPos;
      D3DXVec3Normalize(&nPos,&Pos);
      
      D3DXVec3Normalize(&vecTarget,&vecTarget);
      
      D3DXVECTOR3 toTarget=nPos-vecTarget;
      D3DXVec3Normalize(&toTarget,&toTarget);
        
      //Normalize look 
      D3DXVECTOR3 nLook;
      D3DXVec3Normalize(&nLook,&Look);
        
      //Cross product is axis of rotation
      D3DXVec3Cross(&m_vecAxis,&toTarget,&nLook);
      
      //Dot product is cos of angle of rotation
      m_fAxisAngle=Clamp(-D3DXVec3Dot(&toTarget,&nLook),-1,1);
             
      //Construct axis angle rotation matrix
      D3DXMATRIX T;
      D3DXMatrixRotationAxis(&T,&m_vecAxis,acosf(m_fAxisAngle));
      
      //Compute destination right, up, and look vectors and save in class members
      //OrgRt * T = DestRt
      //OrgUp * T=DestUp
      //OrgLk * T=DestLk
      D3DXVec3TransformCoord(&m_vecTargUp,&Up,&T);
      D3DXVec3TransformCoord(&m_vecTargLook,&Look,&T);
      D3DXVec3TransformCoord(&m_vecTargRight,&Right,&T);
       
      //Hard-coded LERP - later to be based on fastest angular rotation of current ship or camera
      m_fLERP=0.0015f;
    
      //Not used yet
      m_fCurLERP=0.0f;
         
    }
    
    void CCamera::UpdateRotation()
    {
      //Interpolate between current up, right, and look vectors and target up, right, and look vectors by m_fLerp
      //Save result of interpolation back into current up, right, and look vectors
      D3DXVec3Lerp(&Right,&Right,&m_vecTargRight,m_fLERP);
      D3DXVec3Lerp(&Up,&Up,&m_vecTargUp,m_fLERP);
      D3DXVec3Lerp(&Look,&Look,&m_vecTargLook,m_fLERP);
    }
    The linear interpolation works without changing m_fLerp because I'm constantly changing the origin vectors. So the origin gets closer and closer to the target vector without changing the lerp value.
    Last edited by VirtualAce; 07-27-2007 at 05:34 AM.

  13. #13
    Registered User
    Join Date
    Apr 2006
    Posts
    43
    Watch out for numerical drift that might cause your once normalized vectors to be non-unit later on. By constantly transforming the up, look and right vector without ever checking if they need to be renormalized you might get a skew view after some time...depending on how you do the rest of you code it might not be a problem, but I didn't see any renormalization here at least...

    You could instead globally define up as (0, 0, 1) and look as (0, 1, 0) and only store a normalized quaternion with the current orientation for each object instead of storing the current orientation as continously updated vectors, (would be shorter code and use less memory) but I guess you have more code that you would have to rewrite in that case....don't fix what's not broken.

    /f

  14. #14
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    You are right I should be re-normalizing the vectors. Thanks.

    There is code elsewhere in the class that does renormalize the vectors. Any time the viewpoint is changed the vectors are renormalized. Since this code only executes during autopilot and since autopilot orients the object the only way this could creep is if the user continually pressed autopilot on and off without ever touching the controls. But since the angle of rotation in that case would be 0 since the object is already oriented correctly.....this will never creep.
    Last edited by VirtualAce; 08-02-2007 at 02:08 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Yahtzee C++ programme help
    By kenneth_888 in forum C++ Programming
    Replies: 13
    Last Post: 09-05-2007, 02:14 PM
  2. CProg Fantasy Football version pi
    By Govtcheez in forum A Brief History of Cprogramming.com
    Replies: 155
    Last Post: 12-26-2006, 04:30 PM
  3. im extreamly new help
    By rigo305 in forum C++ Programming
    Replies: 27
    Last Post: 04-23-2004, 11:22 PM
  4. Prime Number Generator... Help !?!!
    By Halo in forum C++ Programming
    Replies: 9
    Last Post: 10-20-2003, 07:26 PM
  5. include question
    By Wanted420 in forum C++ Programming
    Replies: 8
    Last Post: 10-17-2003, 03:49 AM