I made a bunch of 3d Math functions for your entertainment. These include: Code (csharp): //increase or decrease the length of vector by size Vector3 AddVectorLength(Vector3 vector, float size){ //create a vector of direction "vector" with length "size" Vector3 SetVectorLength(Vector3 vector, float size){ //caclulate the rotational difference from A to B Quaternion SubtractRotation(Quaternion B, Quaternion A){ //Find the line of intersection between two planes. bool PlanePlaneIntersection(out Vector3 linePoint, out Vector3 lineVec, Vector3 plane1Normal, Vector3 plane1Position, Vector3 plane2Normal, Vector3 plane2Position){ //Get the coordinates of the intersection between a line and a plane bool LinePlaneIntersection(out Vector3 intersection, Vector3 linePoint, Vector3 lineVec, Vector3 planeNormal, Vector3 planePoint){ //Calculate the instersection point of two lines. Returns true if lines intersect, otherwise false. bool LineLineIntersection(out Vector3 intersection, Vector3 linePoint1, Vector3 lineVec1, Vector3 linePoint2, Vector3 lineVec2){ //Two non-parallel lines which may or may not touch each other have a point on each line which lays closest //to each other. This function finds those two points. bool ClosestPointsOnTwoLines(out Vector3 closestPointLine1, out Vector3 closestPointLine2, Vector3 linePoint1, Vector3 lineVec1, Vector3 linePoint2, Vector3 lineVec2){ //This function returns a point which is a projection from a point to a line. Vector3 ProjectPointOnLine(Vector3 linePoint, Vector3 lineVec, Vector3 point){ //This function returns a point which is a projection from a point to a line segment. Vector3 ProjectPointOnLineSegment(Vector3 linePoint1, Vector3 linePoint2, Vector3 point){ //This function returns a point which is a projection from a point to a plane. Vector3 ProjectPointOnPlane(Vector3 planeNormal, Vector3 planePoint, Vector3 point){ //Projects a vector onto a plane. The output is not normalized. Vector3 ProjectVectorOnPlane(Vector3 planeNormal, Vector3 vector){ //Get the shortest distance between a point and a plane. The output is signed so it holds information //as to which side of the plane normal the point is. float SignedDistancePlanePoint(Vector3 planeNormal, Vector3 planePoint, Vector3 point){ //This fuction calculates a signed (+ or - sign instead of being ambiguous) dot product. It is basically used //to figure out whether a vector is positioned to the left or right of another vector. float SignedDotProduct(Vector3 vectorA, Vector3 vectorB, Vector3 normal){ //Calculate the angle between a vector and a plane. The plane is made by a normal vector. //Output is in radians. float AngleVectorPlane(Vector3 vector, Vector3 normal){ //Calculate the dot product as an angle float DotProductAngle(Vector3 vec1, Vector3 vec2){ //Convert a plane defined by 3 points to a plane defined by a vector and a point. //The plane point is the middle of the triangle defined by the 3 points. void PlaneFrom3Points(out Vector3 planeNormal, out Vector3 planePoint, Vector3 pointA, Vector3 pointB, Vector3 pointC){ //Returns the forward vector of a quaternion Vector3 GetForwardVector(Quaternion q) //Returns the up vector of a quaternion Vector3 GetUpVector(Quaternion q) //Returns the right vector of a quaternion Vector3 GetRightVector(Quaternion q) //Gets a quaternion from a matrix Quaternion QuaternionFromMatrix(Matrix4x4 m) //Gets a position from a matrix Vector3 PositionFromMatrix(Matrix4x4 m) //This function translates one object as if it was parented to the other. //Before using this function, the Init() function must be called void TransformWithParent(out Quaternion childRotation, out Vector3 childPosition, Quaternion parentRotation, Vector3 parentPosition, Quaternion startParentRotation, Vector3 startParentPosition, Quaternion startChildRotation, Vector3 startChildPosition) //With this function you can align a triangle of an object with any transform. void PreciseAlign(ref GameObject gameObjectInOut, Vector3 alignWithVector, Vector3 alignWithNormal, Vector3 alignWithPosition, Vector3 triangleForward, Vector3 triangleNormal, Vector3 trianglePosition) //This is an alternative for Quaternion.LookRotation. Instead of aligning the forward and up vector of the game //object with the input vectors, a custom direction can be used instead of the fixed forward and up vectors. void LookRotationExtended(ref GameObject gameObjectInOut, Vector3 alignWithVector, Vector3 alignWithNormal, Vector3 customForward, Vector3 customUp) //Convert a position, direction, and normal vector to a transform void VectorsToTransform(ref GameObject gameObjectInOut, Vector3 positionVector, Vector3 directionVector, Vector3 normalVector){ //This function finds out on which side of a line segment the point is located. int PointOnWhichSideOfLineSegment(Vector3 linePoint1, Vector3 linePoint2, Vector3 point){ //Returns true if a line segment (made up of linePoint1 and linePoint2) is fully or partially in a rectangle bool IsLineInRectangle(Vector3 linePoint1, Vector3 linePoint2, Vector3 rectA, Vector3 rectB, Vector3 rectC, Vector3 rectD){ //Returns true if "point" is in a rectangle made up of RectA to RectD. The line point is assumed to be on the same //plane as the rectangle. If the point is not on the plane, use ProjectPointOnPlane() first. bool IsPointInRectangle(Vector3 point, Vector3 rectA, Vector3 rectC, Vector3 rectB, Vector3 rectD){ //Returns true if line segment made up of pointA1 and pointA2 is crossing line segment made up of //pointB1 and pointB2. The two lines are assumed to be in the same plane. bool AreLineSegmentsCrossing(Vector3 pointA1, Vector3 pointA2, Vector3 pointB1, Vector3 pointB2){ //Returns the pixel distance from the mouse pointer to a line. //Alternative for HandleUtility.DistanceToLine(). Works both in Editor mode and Play mode. float MouseDistanceToLine(Vector3 linePoint1, Vector3 linePoint2){ //Returns the pixel distance from the mouse pointer to a camera facing circle. //Alternative for HandleUtility.DistanceToCircle(). Works both in Editor mode and Play mode. float MouseDistanceToCircle(Vector3 point, float radius){ //This function calculates the acceleration vector in meter/second^2. //Input: position. bool LinearAcceleration(out Vector3 vector, Vector3 position, int samples){ //This function calculates angular acceleration in object space as deg/second^2, encoded as a vector. bool AngularAcceleration(out Vector3 vector, Quaternion rotation, int samples){ //Get y from a linear function, with x as an input. The linear function goes through points //0,0 on the left ,and Qxy on the right. float LinearFunction2DBasic(float x, float Qx, float Qy){ //Get y from a linear function, with x as an input. The linear function goes through points //Pxy on the left ,and Qxy on the right. float LinearFunction2DFull(float x, float Px, float Py, float Qx, float Qy){ //Add rotation B to rotation A. Quaternion AddRotation(Quaternion A, Quaternion B){ //Same as the build in TransformDirection(), but using a rotation instead of a transform Vector3 TransformDirectionMath(Quaternion rotation, Vector3 vector){ //Same as the build in InverseTransformDirection(), but using a rotation instead of a transform Vector3 InverseTransformDirectionMath(Quaternion rotation, Vector3 vector){ //Rotate a vector as if it is attached to an object with rotation "from", which is then rotated to rotation "to". //Similar to TransformWithParent(), but rotating a vector instead of a transform. Vector3 RotateVectorFromTo(Quaternion from, Quaternion to, Vector3 vector){ //Get a point on a Catmull-Rom spline. Vector2 GetPointOnSpline(float percentage, Vector2[] cPoints) { //Finds the intersection points between a straight line and a spline. Solves a Cubic polynomial equation. float[] GetLineSplineIntersections(Vector2[] linePoints, Vector2[] cPoints) { Full code here: https://drive.google.com/file/d/1O0d_pqitpgbFYJG06JO6uAJjudI-QHwn/view?usp=sharing Make sure all input vectors are normalized.
Why not add an Version using extentsion methods? i.e. Code (csharp): public static class Math3D { public static Vector3 addLength(this Vector3 vector, float size){ .... } } then you can use this in your code Code (csharp): Vector3 position = new Vector3(1,1,1); position.addLength(10); // Call the extension method // instead of position = Math3D.addVectorLength(position, 10); It's much shorter and more intuitive, because the extended method will only be displayed in vector3 objects, shorter (addLength vs addVectorLength) and you don't have to pass the vector which is being modiifed to the method ^^
Yea, Extension methods are lovely and allow you to extends "sealed" classes, which can't be extended otherwise or having derive from a class and use the new class instead (who would like to use MyVector3 etc. instead of Vector3 ) On and when we're on it, we in C# use CamelCase for public Methods (and Properties) name Right: public void AddLength(...) Wrong: public void addLength(...) It's a naming convention adopted by most serious C# developers, so it's easier to work and read the Code
I never looked up the proper C# naming conventions but I am aware of it's existence. Maybe this is a good time to get to grips with it.
As in unity the Vector3 is a struct, it's passed by value. So you'll still have to do a position = position.AddLength(10);. But I agree it's still nicer and faster to find using code completion this way.
I added these functions: Code (csharp): //Calculate the instersection point of two lines. Returns true if lines intersect, otherwise false. bool LineLineIntersection(out Vector3 intersection, Vector3 linePoint1, Vector3 lineVec1, Vector3 linePoint2, Vector3 lineVec2){ //Convert a plane defined by 3 points to a plane defined by a vector and a point. //The plane point is the middle of the triangle defined by the 3 points. void PlaneFrom3Points(out Vector3 planeNormal, out Vector3 planePoint, Vector3 pointA, Vector3 pointB, Vector3 pointC){ I still didn't get around to make it work as a extension method...
Code (csharp): //Get the coordinates (world space) of the intersection between a line and a plane Vector3 linePlaneIntersection(Vector3 linePoint, Vector3 lineVec, Vector3 planeNormal, Vector3 planePoint){ ... //line and plane are not parallel if(dotDenominator != 0.0f){ ... } else{ return Vector3.zero; } } Vector3.zero can be a valid intersection point. -- Anyway, respect! It's a very useful set of functions.
I am not sure what you mean. Do you mean there should be a separate variable indicating whether the output is valid or not? There probably should... Edit: Ok, I made all functions output bool false when the output is not valid instead of setting the output to zero or max it out. Edit2: Some functions added Edit 3: Added Code (csharp): PointOnWhichSideOfLineSegment() Edit 4: 6 more functions added
I added a function called LinearAcceleration() which calculates the acceleration / deceleration of any object using only the position as an input. It doesn't require a rigidbody, just a position vector will do. A nice "side effect" is that it automatically calculates centripetal force as well, without the object having to rotate in a perfect circle. It works purely on the change of position over time. Edit: I also added 2 linear functions. These are 2D instead of 3D but I find them quite useful so I included them anyway. It is based on this function: Edit 2: Added AngularAcceleration() function.
Update: some new functions added: Code (CSharp): //Add rotation B to rotation A. public static Quaternion AddRotation(Quaternion A, Quaternion B){ Quaternion C = A * B; return C; } //Same as the build in TransformDirection(), but using a rotation instead of a transform public static Vector3 TransformDirectionMath(Quaternion rotation, Vector3 vector){ Vector3 output = rotation * vector; return output; } //Same as the build in InverseTransformDirection(), but using a rotation instead of a transform public static Vector3 InverseTransformDirectionMath(Quaternion rotation, Vector3 vector){ Vector3 output = Quaternion.Inverse(rotation) * vector; return output; } //Rotate a vector as if it is attached to an object with rotation "from", which is then rotated to rotation "to". //Similar to TransformWithParent(), but rotating a vector instead of a transform. public static Vector3 RotateVectorFromTo(Quaternion from, Quaternion to, Vector3 vector){ //Note: comments are in case all inputs are in World Space. Quaternion Q = SubtractRotation(to, from); //Output is in object space. Vector3 A = InverseTransformDirectionMath(from, vector);//Output is in object space. Vector3 B = Q * A; //Output is in local space. Vector3 C = TransformDirectionMath(from, B); //Output is in world space. return C; } Note that the RotateVectorFromTo() function might be optimized. Let me know if you have any suggestions.
Thanks for sharing your work! Small bit of feedback: RotDiffToSpeedVec() is called a couple of times, but isn't implemented here.
Nice work. When you're ready to speed it up a ton, check this out: http://www.performancesimulations.c...ses-in-unitys-physics-or-any-math-heavy-code/
I tested the LineLineIntersection function and it seems not to work properly. These 2 lines should return "true" but the function says there is no intersection: linepoint1: (5.0, 0.0, -10.0), lineVec1: (5.0, 0.0, 10.0) linepoint2: (10.0, 0.0, 5.0), lineVec2: (-10.0, 0.0, 5.0) Or did I get the parameters wrong?
I never had much luck with that function in 3D and instead use ClosestPointsOnTwoLines. If the lines truly intersect you'll get the point from it.
There's a flaw in the algorithm. 2 lines in 3-space intersect if they're coplanar and NOT parallel. The algorithm determines if they're coplanar... but then goes on to get the distance along line 1 from its point that line 2 intersects it... and it assumes if that value is not between 0 and 1, they don't intersect... what? This forces the inputs to have to have their points defined really near each other. How you can test if they're not parallel is if crossVec1and2 is not near a zero vector (sqrMagnitude won't be 0), since a zero vector results when you cross 2 vectors that are parallel. Rewritten: Code (csharp): public static bool LineLineIntersection(out Vector3 intersection, Vector3 linePoint1, Vector3 lineVec1, Vector3 linePoint2, Vector3 lineVec2){ Vector3 lineVec3 = linePoint2 - linePoint1; Vector3 crossVec1and2 = Vector3.Cross(lineVec1, lineVec2); Vector3 crossVec3and2 = Vector3.Cross(lineVec3, lineVec2); float planarFactor = Vector3.Dot(lineVec3, crossVec1and2); //is coplanar, and not parrallel if(Mathf.Abs(planarFactor) < 0.0001f && crossVec1and2.sqrMagnitude > 0.0001f) { float s = Vector3.Dot(crossVec3and2, crossVec1and2) / crossVec1and2.sqrMagnitude; intersection = linePoint1 + (lineVec1 * s); return true; } else { intersection = Vector3.zero; return false; } } Which you can also see here in my framework: https://github.com/lordofduct/spacepuppy-unity-framework/blob/master/SpacepuppyBase/Geom/Line.cs
Is there a function that create rectangle points from a rectangle position and size ? it will be very powerful, So this will simplify the use of IsPointInRectangle function. thanks
Added a function which finds the intersection points between a line and a Catmull-rom spline. It basically reverse solves a spline function. So instead of providing a value (0-1) to get the location on a spline, you input the location on a spline and get the corresponding 0-1 value. Sounds easy but this is not trivial. Implementations based on this: http://lifeinacubicleblog.com/2016/...ne-intersection-part-2-mathematical-approach/ Use case1: Create a gauge with a non-linear scale by defining an array with needle angles vs the number it should point at. The array creates a spline. Driving the needle with a float in range 0 to 1 gives an unpredictable result. Instead, use the GetLineSplineIntersections() function to find the angle the gauge needle should have for a given number it should point at. In this case, cPoints should contain x for angle and y for scale number. Make a horizontal line at the given scale number (y) you want to find the needle angle for. The returned float is a percentage location on the spline (range 0 to 1). Plug this value into the GetPointOnSpline() function to get the x coordinate which represents the needle angle. Use case 2: Make a gauge follow a non-linear animation, for example the (Exhaust Gas Temperature) EGT of a jet engine during startup. A video of a the event would be recorded and used to capture sample points consisting of EGT vs time. The time (x) and EGT (y) values would then be used to create a spline, allowing smooth interpolation between the original sample points. The line-spline intersection function can then be used to get the EGT for any point in time. More info and a demo project can be found on my blog: https://bitbarrelmedia.wordpress.com/2017/11/07/driving-non-linear-gauges/
Awesome library!!! Should one simply copy the code from the wiki page or is there a git repo or Unity Asset?
Please note, all content published on the http://wiki.unity3d.com/index.php/3d_Math_functions is is available under Creative Commons Attribution Share Alike. That means the source code of your project also must be published if you use it. Elecman, it would be nice if you publish your code under MIT license or similar
And that is the problem Unity Wiki has now moved, the links have broken and ths link is still the main hit from Google
web archive: https://web.archive.org/web/20210507045029/http://wiki.unity3d.com/index.php/3d_Math_functions unity wiki backup zip from 2017 https://github.com/UnityCommunity/UnityLibrary/issues/16#issuecomment-321150087
I uploaded the latest file to my google drive. You can get the link from the first post or from my signature.