Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Perpendicular vectors in a 3D space

Discussion in 'Scripting' started by SecondDegreePerm, Aug 11, 2019.

  1. SecondDegreePerm

    SecondDegreePerm

    Joined:
    Jul 2, 2017
    Posts:
    42
    Hi All,

    I have two points in 3D space that I am using the Lerp function between to form a line. I want to know how best to identify any and all perpendicular vectors for that line so I may access any of those lines. Like if you had a circle bisecting the line perpendicularly, such that the centre of the circle was a point on the line, what would all the unit vectors be from the centre of the circle outwards? I have tried using the cross product but this only gives one very specific perpendicular point, I want to be able to access any perpendicular vector

    Thanks in Advance,
    Daniel
     
  2. Aseemy

    Aseemy

    Joined:
    Aug 22, 2015
    Posts:
    204
    I dont fully understand your requirement. wouldnt there be infinite number of such vectors?
     
  3. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    It's a bit hard to tell what you want, but if you're only worried about the relative directions from your given vector in space, my advice would be to use an empty GameObject/Transform, place it in the position and rotation you like, and then run Transform.TransformPoint and Transform.TransformDirection to get the values you need without all of the math necessary.
     
  4. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,594
  5. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    (Warning: I'm not a mathematician, so please forgive that messy description).

    As pointed out by @Aseemy, there is an infinite number of vectors you can find that satisfy the requirement.

    Any V that solves the equation
    dot(D, V) = 0, where D is the direction of your line, or P2-P1 (or vice versa), is such perpendicular vector to the line.

    You can then normalize any V that solves the equation in order to get one of the desired results (you mentioned unit vectors).

    Of course, if at least one of both, V or D happens to be (0,0,0), the equation evaluates to true no matter what the other value is.


    The [unit] vectors would be the solutions from above. They have no notion of describing a particular position, as they only represent directions.

    However, if the center is Px, you can get to any point on that imaginary circle using Px + (normalize(V) * r).
     
    Last edited: Aug 11, 2019
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,385
    First I'm going to say that in 3-space we don't say "perpendicular" we say "orthogonal" (orthogonal is defined as meaning 'relating to or using right angles'). The reason is as everyone keeps bringing up... a single line has an infinite number of orthogonal lines to it since you can take any line that is 90 degrees off the first and then spin it around the first line as its axis and get an infinite number of lines.

    If you want an equation to get ANY of those lines using vectors. Easy, take the vector from p1 to p2, rotate it 90 degrees. That can be done as easy as this:
    Code (csharp):
    1. var orthogonalVector = Vector3.RotateTowards(v, -v, Mathf.PI / 2f, 0f);//this method uses radians, not degrees. pi/2 is 90 degrees
    Then that vector can be multiplied by a Quaternion created from an angle/axis of the original vector from p1->p2.

    Code (csharp):
    1. var anotherOrthogonalVector = Quaternion.AngleAxis(Random.value * 360f, v) * orthogonalVector;
    There is many other ways to do it as well... but using built in functions easily at your disposal this seemed like one you could do in very few steps and is very readable about what it's doing.

    1) rotate v towards -v by 90 degrees
    2) rotate new ov around v

    ...

    The thing I'm wondering is... what are you needing this for?

    I have a strong feeling that since you didn't realize there are infinite orthogonal/perpendicular vectors that maybe you're thinking your problem all wrong.
     
    Last edited: Aug 11, 2019
    Suddoha likes this.
  7. SecondDegreePerm

    SecondDegreePerm

    Joined:
    Jul 2, 2017
    Posts:
    42
    I'm trying to code a parallel bezier path using the Tiller-Hanson method. I thought that, give two points and a vector which describes the line those two points, there would be an infinite number of perpendicular points coming any given point on that line. I thought, and I may be wrong, that those points have the constraint of having to come from the same plane, and the infinite number of perpendicular vectors is infinite in the same way that there are an infinite number of degrees in a circle. I want to be able in order to help make make this parallel bezier path creator and find.

    Right now when I am using the cross product it is projecting the anchor and control points on a plane separate to the plane that the origin lines exist in. I want the offset of the new curve to be on the same plane as the lines that make up the original bezier curve.
    upload_2019-8-12_9-36-5.png
    upload_2019-8-12_9-37-4.png
    Using the cross product to get the perpendicular angle does not create the desired behaviour. The white shapes represent where the control and anchor points of the new curve would be. These are found by finding the intersection of the offset lerps from the original curve. I thought it would be a good idea, just so I feel like I can learn manipulation of angles and perpendicular lines, that I could have a slider that when creating the offset lerps to change which perpendicular vector I am using for the creation of the parallel bezier curve. Strictly the desired behaviour here is more simply, i just require the new offset lines to be on the same plane just offset to the originator lines.

    Apologies for not making things clearer. I may have also stumbled a bit here in trying to make things clearer, so if anything seems wrong/unclear please don't hesitate to ask!
     
  8. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,594
    Since you need a plane to draw Bezier curve, you need two vectors, to define that plane. You can not create plane from two points. You need some reference. For example where is your virtual up.

    But if you have two vectors, that allows you to derive your plane, in desired orientation.
     
  9. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Now that's a little clearer, though I had to look up the Tiller-Hanson method.

    It seems that you moved the new control points in the wrong direction. It appears to be the curve just with an offset though.

    For the method described, and for the example at hand (endpoints and control points being on the same plane) you already have the plane on which the new points have to lie.

    Using the direction of the lines which connect the points as well as considering the plane's, you should actually be able to determine the direction vector which is required to move the connecting lines in-/outwards. Then, calculate the intersections in order to get the new control points.

    If you want to do that for curves that do not just lie on a plane, it seems that you could just get the result by applying the method to 3 connected points at a time, from which you could always build a plane and its normal vector. Then, just move the lines etc.
    I'm not entirely sure that'd work though.

    One thing you could try:
    I'm wondering if duplication of the points + scaling them propotionally would yield the results you're looking for. If that worked, you could simply use transforms in order to make life easier.
     
    Last edited: Aug 12, 2019
    Antypodish likes this.
  10. SecondDegreePerm

    SecondDegreePerm

    Joined:
    Jul 2, 2017
    Posts:
    42
    This unfortunately doesn't produce the desired result. The offset is not consistent.

    upload_2019-8-12_16-16-43.png

    I am afraid I don't understand what you mean by I already have the plane on which the new points have to lie. What plane would that be? Since its 3D aren't there a whole lot of planes? It doesnt matter to me what plane is picked for this generated path, at least initially. I want the perpendicular paths to always be on the same plane- I ultimately want to generate a parallel path either side of the originator path. How are planes even expressed within Unity/C#?
     
  11. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,594
    Just pick fixed plane. X/Z, or X/Y for simplicity. And try build your Bezier line there.
    Then you can use local space, to draw your Bezier points. After that, you can orient created line as required.
     
  12. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Okay, worth a try. It just came to my mind, didn't think much about it. Now that you've shown that, it suddenly makes sense that it can stretch that whole thing... Silly me. :p

    Well, yes. If you only take 2 distinct points, you'll have an infinite number of planes which they lie on.

    However, the curve you've shown in your first example seems to lie on a plane with its endpoints and its control points (sort of a 2D curve in 3D space). If that's the case you take 3 of the points and build 2 linearly independent vectors, from which you can already determine the normal of that plane using the cross product.

    Next, take that normal vector and the direction of the line which connects two points, and use the cross product again. Note that a different order of the arguments for the dot product produces a different result. The cross product is anti-commutative, i.e. switching the order returns a vector pointing in the opposite direction.
    The result is the direction that you need to use for the offsets.
     
    Last edited: Aug 12, 2019
  13. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Using the initial example with 2 endpoints, 2 control points:

    Endpoint E1, Endpoint E2, Control point C1, Control point C2.

    1) V1 = C2 - E1, and V2 = C1 - E1. The results V1 and V2 lie on a plane.
    Make sure V1 and V2 are linearly independent before you continue.
    2) Calculate cross(V1, V2), which produces N (upwards in your example), the normal that's perpendicular to the span of V1 and V2.
    3) Choose an order, for example E1, C1, C2, E2.
    4) Calculate the differences (the direction from one to the subsequent) in that order, i.e. C1-E1, C2-C1, E2-C2.
    5) Calculate cross(N, D1), which produces another normal for the span of N and D1, that one would point "outwards", so let's call it NO. "Inwards" is just cross(N, D1) * -1 or simply cross(D1, N), as the cross product is anti-commutative, let's call that NI. We'll stick to NO for the remaining steps though.
    6) Normalize NO and calculate the offset points: E1 + NO*k = E1' and C1 + NO*k = C1', where k is the offset.
    7) Repeat 5) with cross(N, D2) and cross (N, D3)
    8) Using the offset control points, you can now calculate the intersections in order to find the actual new control points. The new endpoints are already there: E1' and E2'.

    Sorry for any mistakes, I've just written it down and haven't really tried it. But I think it should work. Maybe it can be shortened.
     
    Last edited: Aug 12, 2019
    Antypodish likes this.
  14. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,594
    Probably I would do such in different way, but @Suddoha gave nice break down of steps.
    I have followed to mid step of 6th point, but didn't want stretch my brain cells beyond :)
    Seams logical solution.
     
  15. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Here's the reference post on math.stackexchange discussing the Tiller and Hanson method, for which I came up with these steps. It's not a perfect solution, as that Tiller and Hanson method is also just an approximation. Somewhere I've read that there's no way to offset them accurately (I think it was in a linked post) unless the "curve" happens to be a straight line of course.

    Step 6 are just the orthogonal vectors pointing towards the red lines.

    There might be edge cases that need some special handling, but that's too much to test right now.
     
    Last edited: Aug 12, 2019
    Antypodish likes this.
  16. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,594
    In meantime, since we are on topic of Bezier curve, here is nice thread that someone may find useful in future.
    Bezier Solution [Open Source]
     
    Suddoha likes this.
  17. SecondDegreePerm

    SecondDegreePerm

    Joined:
    Jul 2, 2017
    Posts:
    42
    I'll give your suggestion a try! Might take me a little while to implement but I'll let you know how it works after I've given it a shot.

    I've actually been using the asset below, which has been good for most of my needs so far.
    https://assetstore.unity.com/packages/tools/utilities/b-zier-path-creator-136082
     
    Antypodish likes this.