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
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

How to calculate new direction from ray cast onto a surface?

Discussion in 'Scripting' started by Sabo, Jan 9, 2017.

  1. Sabo

    Sabo

    Joined:
    Nov 7, 2009
    Posts:
    151
    Not sure if this is the right forum for this question.

    I need help with some linear algebra. Imagine an object (bullet etc) flying in 3D space. When the object collides with a surface it should continue to travel parallel to the surface, rince and repeat, until its travel length has been reached or it makes a "head on" collision, i.e., the direction of the object is the same as the negative normal of the surface (not likely to happen). The direction of the object along the surface must be related to the direction the object had when it reached the surface, and this is where I need help.

    I am (I think) able to do the math in 2D. Below is a code example for 2D to illustrate what it is that I am looking to accomplish in 3D.

    Code (CSharp):
    1. var hit = Physics2D.Raycast(rayOrigin, Vector2.right, rayLength, CollisionMask);
    2. if (hit)
    3. {
    4.     // Get the rotation angle.
    5.     var rotationAngle = Vector2.Angle(hit.normal, Vector2.up);
    6.     if (rotationAngle > 90.0f)
    7.     {
    8.         rotationAngle -= 180.0f;
    9.     }
    10.  
    11.     // Get the new direction and length.
    12.     var direction = Quaternion.Euler(0.0f, 0.0f, rotationAngle) * Vector2.right;
    13.     length -= hit.distance;
    14. }
    Can someone help me figure out how to accomplish the same in 3D space?

    Side question: Can the direction calculation above be simplified?
     
    Last edited: Jan 9, 2017
  2. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,739
  3. Sabo

    Sabo

    Joined:
    Nov 7, 2009
    Posts:
    151
    I must have been unclear. I want a vector that is parallel to the surface. Will change the wording in of "travel along the surface" to "travel parallel to the surface" in OP.
     
  4. Polymorphik

    Polymorphik

    Joined:
    Jul 25, 2014
    Posts:
    599
    Hello,

    This is not Linear Algebra it is Trigonometry with a little sprinkle of Calculus 3 or Vector Math.

    I attached a Unity Package so you can take a look.

    The code

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. [ExecuteInEditMode]
    5. public class Raytrace : MonoBehaviour {
    6.     [SerializeField]
    7.     float m_Distance = 10.0F;
    8.     void Update() {
    9.         Ray ray = new Ray(this.transform.position, this.transform.forward);
    10.         RaycastHit hit;
    11.  
    12.         // Raytrace is RED
    13.         Debug.DrawLine(ray.origin, ray.origin + ray.direction * this.m_Distance, Color.red);
    14.  
    15.         // Are we hitting a surface?
    16.         if(Physics.Raycast(ray, out hit, this.m_Distance)) {
    17.             // Get the angle between the direction of our raytrace and the normal.
    18.             // Since the Normal is always _|_ to the surface we have to
    19.             // Find the angle between the normal
    20.             // and the direction of our ray coming FROM the Noraml
    21.             // hence why we have to make it negative so it goes
    22.             // the other direction
    23.             float angle = Vector3.Angle(-ray.direction, hit.normal);
    24.  
    25.             // Get the height from the point of contact to the height of the our
    26.             // Raytrace origin.
    27.             // The reason why we need this is so we can calculate the point
    28.             // where or Normal extended to some height is level with our point or origin
    29.             // meaning the 3D point in space where the Ray begins.
    30.             float height = hit.distance * Mathf.Sin(Mathf.PI / 2.0F - angle * Mathf.Deg2Rad);
    31.            
    32.             // We now have a 3D Vector that is level with our origin.
    33.             // This allows us to create in our head a Triangle.
    34.             // If you take a look at the Scene View Window
    35.             // You will notice I made everything resemble a triangle to
    36.             // make the calculations easier.
    37.             Vector3 normalEndPoint = hit.point + hit.normal * height;
    38.  
    39.             // Normal is BLUE
    40.             Debug.DrawLine(hit.point, normalEndPoint, Color.blue);
    41.  
    42.             // Calculate the surface vector. This is going to be a unit vector
    43.             // so, you can then do in your calculations transform.forward = surfaceVector
    44.             // so you can 'ride' along the surface.
    45.             Vector3 surfaceUnitVector = (normalEndPoint - ray.origin).normalized;
    46.  
    47.             // Surface Vector is GREEN
    48.             Debug.DrawRay(hit.point, surfaceUnitVector, Color.green);
    49.         }
    50.     }
    51. }
    52.  
     

    Attached Files:

    nbg_yalta and Sabo like this.
  5. Polymorphik

    Polymorphik

    Joined:
    Jul 25, 2014
    Posts:
    599
    Hope that helps
     
    Sabo likes this.
  6. Sabo

    Sabo

    Joined:
    Nov 7, 2009
    Posts:
    151
    I got my introduction to vector math in my linear algebra classes, and wikipedia seems to agree with me, "Vector spaces are the subject of linear algebra ...". Was a long time ago, and I am no math guru (hence this post) so you are probably right.

    I just had a look at the package you included. Seems to be exactly what I was looking for (I just hope that I have defined the problem correctly). And the code and math is so clean! Now I begin to worry that my own math for the 2D solution is very suboptimal...

    Thanks a ton for the code and package. It is very highly appreciated. You might have saved my day and in a very sexy way.
     
  7. Polymorphik

    Polymorphik

    Joined:
    Jul 25, 2014
    Posts:
    599
    That's odd you got introduced to Vector math in linear algebra as it is part of Calculus series...how did you ever do integral calculus without an understanding of Vector Calculus? From what I remember of Linear we did Vectors for a few weeks and went into abstract vector fields and matrices.

    Either way its all math. Glad I could help, the way I went about to tackle this problem was I opened up my Trig book and got the equation for the AAS since you know the distance of 1 side (the ray trace from the RaycastHit.distance value) and if you solve for 1 angle you can find the other as the other would be 90-Theta. Hence why my calculation has 90.0F-angle. And the Calculus part was testing the Vectors using the angle between 2 vectors cos(theta) = A DOT B / ||A||*||B|| etc. It was a cool little exercise.

    Good luck with your project!
     
    Sabo likes this.
  8. Sabo

    Sabo

    Joined:
    Nov 7, 2009
    Posts:
    151
    Curious, the line
    Code (CSharp):
    1. float height = hit.distance * Mathf.Sin(Mathf.PI / 2.0F - angle * Mathf.Deg2Rad);
    is that not the same as
    Code (CSharp):
    1. float height = hit.distance * Mathf.Cos(angle * Mathf.Deg2Rad);
    ?

    A quick test verifies that it seems to be the same (with the potential to be a tiny bit more accurate due to less floating operations), but is it always true? Drawing the triangle on paper is telling me it should be correct, but would love if someone could confirm it.
     
  9. Polymorphik

    Polymorphik

    Joined:
    Jul 25, 2014
    Posts:
    599
    Looking at my triangle the Cosine would be the distance from the origin point to normal end point in 2D the problem is knowing that distance does not help you as you do not know the position of the normal end point. I.E. which direction does the distance travel along in 3D space? I find the height first then find the end point then create a vector from the origin to that Normal End point (the blue line) and the get the unity vector from that. The distance from the origin to the normal end point is not required as you don't care for the purposes of your needs all you want is the direction to face.
     
  10. Sabo

    Sabo

    Joined:
    Nov 7, 2009
    Posts:
    151
    I believe you missed that I was using different angles for the Sin and the Cos functions?
    The Sin solution use "Mathf.PI / 2.0F - angle * Mathf.Deg2Rad"
    The Cos solution use "angle * Mathf.Deg2Rad"

    Since we are working with a right angle we have the following:
    A = 90 degrees
    B = angle degrees (the angle we calculated between the normal and the reversed direction vector)
    C = 180 - A - B = 90 - B
    a = hit.distance
    c = length we are looking for

    It then follows that
    c = a * Mathf.Sin(C * Mathf.Deg2Rad) = a * Mathf.Cos(B * Mathf.Deg2Rad)

    Dividing both sides with "a" and we are left with
    Mathf.Sin(C * Mathf.Deg2Rad) = Mathf.Cos(B * Mathf.Deg2Rad)

    Mathf.Sin(90 - angle * Mathf.Deg2Rad) = Mathf.Cos(angle * Mathf.Deg2Rad)
    Mathf.Sin(Mathf.PI / 2.0F - angle * Mathf.Deg2Rad) = Mathf.Cos(angle * Mathf.Deg2Rad)

    Or?
     
  11. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    What...? Vector is part of linear algebra and you can do calculus without using vectors; calculus is the study of change using differentials and integrals, it does not have to involve vectors. But you also have both fields combined, and that's Vector Calculus.
     
  12. Polymorphik

    Polymorphik

    Joined:
    Jul 25, 2014
    Posts:
    599
    Linear Algebra is the teaching of Vector Spaces, Sub Spaces etc...yes you do do Vector math somewhat but you learn that in Calculus and Trigonometry when you learn about the concept of 'direction'. Physics requires you to have taken Calculus for this very reason NOT Linear Algebra they are not synonymous to each other as they are very different fields of study. One is more abstract. I cannot recall a single time I did any computations in Linear Algebra all I ever* did was prove a subset was part of an other set. We used vectors to illustrate a graphical representation (sometimes if possible) but that was it.
     
  13. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    I maintain: Vector is part of Linear Algebra, not Calculus.

    The order or how the concepts are introduced does not matter, Linear Algebra (study of vectors and matrices) and Calculus (study of change) are different fields.

    Of course, you can have overlaps and mix of different fields for practical reasons or educational purposes.