Skip to content

Instantly share code, notes, and snippets.

@bzgeb
Created March 13, 2013 18:33
Show Gist options
  • Save bzgeb/5154836 to your computer and use it in GitHub Desktop.
Save bzgeb/5154836 to your computer and use it in GitHub Desktop.
Util
/*
Copyright (c) 2008, Rune Skovbo Johansen & Unity Technologies ApS
See the document "TERMS OF USE" included in the project folder for licencing details.
*/
using UnityEngine;
using System.Collections;
public class Util {
public static bool IsSaneNumber(float f) {
if (System.Single.IsNaN(f)) return false;
if (f==Mathf.Infinity) return false;
if (f==Mathf.NegativeInfinity) return false;
if (f>1000000000000) return false;
if (f<-1000000000000) return false;
return true;
}
public static Vector3 Clamp(Vector3 v, float length) {
float l = v.magnitude;
if (l > length) return v / l * length;
return v;
}
public static float Mod(float x, float period) {
float r = x % period;
return (r>=0?r:r+period);
}
public static int Mod(int x, int period) {
int r = x % period;
return (r>=0?r:r+period);
}
public static float Mod(float x) { return Mod(x, 1); }
public static int Mod(int x) { return Mod(x, 1); }
public static float CyclicDiff(float high, float low, float period, bool skipWrap) {
if (!skipWrap) {
high = Mod(high,period);
low = Mod(low,period);
}
return ( high>=low ? high-low : high+period-low );
}
public static int CyclicDiff(int high, int low, int period, bool skipWrap) {
if (!skipWrap) {
high = Mod(high,period);
low = Mod(low,period);
}
return ( high>=low ? high-low : high+period-low );
}
public static float CyclicDiff(float high, float low, float period) { return CyclicDiff(high, low, period, false); }
public static int CyclicDiff(int high, int low, int period) { return CyclicDiff(high, low, period, false); }
public static float CyclicDiff(float high, float low) { return CyclicDiff(high, low, 1, false); }
public static int CyclicDiff(int high, int low) { return CyclicDiff(high, low, 1, false); }
// Returns true is compared is lower than comparedTo relative to reference,
// which is assumed not to lie between compared and comparedTo.
public static bool CyclicIsLower(float compared, float comparedTo, float reference, float period) {
compared = Mod(compared,period);
comparedTo = Mod(comparedTo,period);
if (
CyclicDiff(compared,reference,period,true)
<
CyclicDiff(comparedTo,reference,period,true)
) return true;
return false;
}
public static bool CyclicIsLower(int compared, int comparedTo, int reference, int period) {
compared = Mod(compared,period);
comparedTo = Mod(comparedTo,period);
if (
CyclicDiff(compared,reference,period,true)
<
CyclicDiff(comparedTo,reference,period,true)
) return true;
return false;
}
public static bool CyclicIsLower(float compared, float comparedTo, float reference) {
return CyclicIsLower(compared, comparedTo, reference, 1); }
public static bool CyclicIsLower(int compared, int comparedTo, int reference) {
return CyclicIsLower(compared, comparedTo, reference, 1); }
public static float CyclicLerp(float a, float b, float t, float period) {
if (Mathf.Abs(b-a)<=period/2) { return a*(1-t)+b*t; }
if (b<a) a -= period; else b -= period;
return Util.Mod(a*(1-t)+b*t);
}
public static Vector3 ProjectOntoPlane(Vector3 v, Vector3 normal) {
return v-Vector3.Project(v,normal);
}
public static Vector3 SetHeight(Vector3 originalVector, Vector3 referenceHeightVector, Vector3 upVector) {
Vector3 originalOnPlane = ProjectOntoPlane(originalVector, upVector);
Vector3 referenceOnAxis = Vector3.Project(referenceHeightVector, upVector);
return originalOnPlane + referenceOnAxis;
}
public static Vector3 GetHighest(Vector3 a, Vector3 b, Vector3 upVector) {
if (Vector3.Dot(a,upVector) >= Vector3.Dot(b,upVector)) return a;
return b;
}
public static Vector3 GetLowest(Vector3 a, Vector3 b, Vector3 upVector) {
if (Vector3.Dot(a,upVector) <= Vector3.Dot(b,upVector)) return a;
return b;
}
public static Matrix4x4 RelativeMatrix(Transform t, Transform relativeTo) {
return relativeTo.worldToLocalMatrix * t.localToWorldMatrix;
}
public static Vector3 TransformVector(Matrix4x4 m, Vector3 v) {
return m.MultiplyPoint(v) - m.MultiplyPoint(Vector3.zero);
}
public static Vector3 TransformVector(Transform t, Vector3 v) {
return TransformVector(t.localToWorldMatrix,v);
}
public static void TransformFromMatrix(Matrix4x4 matrix, Transform trans) {
trans.rotation = Util.QuaternionFromMatrix(matrix);
trans.position = matrix.GetColumn(3); // uses implicit conversion from Vector4 to Vector3
}
public static Quaternion QuaternionFromMatrix(Matrix4x4 m) {
// Adapted from: http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
Quaternion q = new Quaternion();
q.w = Mathf.Sqrt( Mathf.Max( 0, 1 + m[0,0] + m[1,1] + m[2,2] ) ) / 2;
q.x = Mathf.Sqrt( Mathf.Max( 0, 1 + m[0,0] - m[1,1] - m[2,2] ) ) / 2;
q.y = Mathf.Sqrt( Mathf.Max( 0, 1 - m[0,0] + m[1,1] - m[2,2] ) ) / 2;
q.z = Mathf.Sqrt( Mathf.Max( 0, 1 - m[0,0] - m[1,1] + m[2,2] ) ) / 2;
q.x *= Mathf.Sign( q.x * ( m[2,1] - m[1,2] ) );
q.y *= Mathf.Sign( q.y * ( m[0,2] - m[2,0] ) );
q.z *= Mathf.Sign( q.z * ( m[1,0] - m[0,1] ) );
return q;
}
public static Matrix4x4 MatrixFromQuaternion(Quaternion q) {
return CreateMatrix(q*Vector3.right, q*Vector3.up, q*Vector3.forward, Vector3.zero);
}
public static Matrix4x4 MatrixFromQuaternionPosition(Quaternion q, Vector3 p) {
Matrix4x4 m = MatrixFromQuaternion(q);
m.SetColumn(3,p);
m[3,3] = 1;
return m;
}
public static Matrix4x4 MatrixSlerp(Matrix4x4 a, Matrix4x4 b, float t) {
t = Mathf.Clamp01(t);
Matrix4x4 m = MatrixFromQuaternion(Quaternion.Slerp(QuaternionFromMatrix(a),QuaternionFromMatrix(b),t));
m.SetColumn(3,a.GetColumn(3)*(1-t)+b.GetColumn(3)*t);
m[3,3] = 1;
return m;
}
public static Matrix4x4 CreateMatrix(Vector3 right, Vector3 up, Vector3 forward, Vector3 position) {
Matrix4x4 m = Matrix4x4.identity;
m.SetColumn(0,right);
m.SetColumn(1,up);
m.SetColumn(2,forward);
m.SetColumn(3,position);
m[3,3] = 1;
return m;
}
public static Matrix4x4 CreateMatrixPosition(Vector3 position) {
Matrix4x4 m = Matrix4x4.identity;
m.SetColumn(3,position);
m[3,3] = 1;
return m;
}
public static void TranslateMatrix(ref Matrix4x4 m, Vector3 position) {
m.SetColumn(3,(Vector3)(m.GetColumn(3))+position);
m[3,3] = 1;
}
public static Vector3 ConstantSlerp(Vector3 from, Vector3 to, float angle) {
float value = Mathf.Min(1, angle / Vector3.Angle(from, to));
return Vector3.Slerp(from, to, value);
}
public static Quaternion ConstantSlerp(Quaternion from, Quaternion to, float angle) {
float value = Mathf.Min(1, angle / Quaternion.Angle(from, to));
return Quaternion.Slerp(from, to, value);
}
public static Vector3 ConstantLerp(Vector3 from, Vector3 to, float length) {
return from + Clamp(to-from, length);
}
public static Vector3 Bezier(Vector3 a, Vector3 b, Vector3 c, Vector3 d, float t) {
Vector3 ab = Vector3.Lerp(a,b,t);
Vector3 bc = Vector3.Lerp(b,c,t);
Vector3 cd = Vector3.Lerp(c,d,t);
Vector3 abc = Vector3.Lerp(ab,bc,t);
Vector3 bcd = Vector3.Lerp(bc,cd,t);
return Vector3.Lerp(abc,bcd,t);
}
public static GameObject Create3dText(Font font, string text, Vector3 position, float size, Color color) {
// Create new object to display 3d text
GameObject myTextObject = new GameObject("text_"+text);
// Add TextMesh and MeshRenderer components
TextMesh textMeshComponent = myTextObject.AddComponent(typeof(TextMesh)) as TextMesh;
myTextObject.AddComponent(typeof(MeshRenderer));
// Set font of TextMesh component (it works according to the inspector)
textMeshComponent.font = font;
myTextObject.renderer.material = font.material;
myTextObject.renderer.material.color = color;
// Set the text string of the TextMesh component (it works according to the inspector)
textMeshComponent.text = text;
myTextObject.transform.localScale = Vector3.one*size;
myTextObject.transform.Translate(position);
return myTextObject;
}
public static float[] GetLineSphereIntersections(Vector3 lineStart, Vector3 lineDir, Vector3 sphereCenter, float sphereRadius) {
/*double a = lineDir.sqrMagnitude;
double b = 2 * (Vector3.Dot(lineStart, lineDir) - Vector3.Dot(lineDir, sphereCenter));
double c = lineStart.sqrMagnitude + sphereCenter.sqrMagnitude - 2*Vector3.Dot(lineStart, sphereCenter) - sphereRadius*sphereRadius;
double d = b*b - 4*a*c;
if (d<0) return null;
double i1 = (-b - System.Math.Sqrt(d)) / (2*a);
double i2 = (-b + System.Math.Sqrt(d)) / (2*a);
if (i1<i2) return new float[] {(float)i1, (float)i2};
else return new float[] {(float)i2, (float)i1};*/
float a = lineDir.sqrMagnitude;
float b = 2 * (Vector3.Dot(lineStart, lineDir) - Vector3.Dot(lineDir, sphereCenter));
float c = lineStart.sqrMagnitude + sphereCenter.sqrMagnitude - 2*Vector3.Dot(lineStart, sphereCenter) - sphereRadius*sphereRadius;
float d = b*b - 4*a*c;
if (d<0) return null;
float i1 = (-b - Mathf.Sqrt(d)) / (2*a);
float i2 = (-b + Mathf.Sqrt(d)) / (2*a);
if (i1<i2) return new float[] {i1, i2};
else return new float[] {i2, i1};
}
}
public class DrawArea {
public Vector3 min;
public Vector3 max;
public Vector3 canvasMin = new Vector3(0,0,0);
public Vector3 canvasMax = new Vector3(1,1,1);
//public float drawDistance = 1;
public DrawArea(Vector3 min, Vector3 max) {
this.min = min;
this.max = max;
}
public virtual Vector3 Point(Vector3 p) {
return Camera.main.ScreenToWorldPoint(
Vector3.Scale(
new Vector3(
(p.x-canvasMin.x) / (canvasMax.x-canvasMin.x),
(p.y-canvasMin.y) / (canvasMax.y-canvasMin.y),
0
),
max-min
)+min
+Vector3.forward * Camera.main.nearClipPlane *1.1f
);
}
public void DrawLine(Vector3 a, Vector3 b, Color c) {
GL.Color(c);
GL.Vertex(Point(a));
GL.Vertex(Point(b));
}
public void DrawRay(Vector3 start, Vector3 dir, Color c) {
DrawLine(start, start+dir, c);
}
public void DrawRect(Vector3 a, Vector3 b, Color c) {
GL.Color(c);
GL.Vertex(Point(new Vector3(a.x,a.y,0)));
GL.Vertex(Point(new Vector3(a.x,b.y,0)));
GL.Vertex(Point(new Vector3(b.x,b.y,0)));
GL.Vertex(Point(new Vector3(b.x,a.y,0)));
}
public void DrawDiamond(Vector3 a, Vector3 b, Color c) {
GL.Color(c);
GL.Vertex(Point(new Vector3(a.x,(a.y+b.y)/2,0)));
GL.Vertex(Point(new Vector3((a.x+b.x)/2,b.y,0)));
GL.Vertex(Point(new Vector3(b.x,(a.y+b.y)/2,0)));
GL.Vertex(Point(new Vector3((a.x+b.x)/2,a.y,0)));
}
public void DrawRect(Vector3 corner, Vector3 dirA, Vector3 dirB, Color c) {
GL.Color(c);
Vector3[] dirs = new Vector3[]{dirA,dirB};
for (int i=0; i<2; i++) {
for (int dir=0; dir<2; dir++) {
Vector3 start = corner + dirs[(dir+1)%2]*i;
GL.Vertex(Point(start));
GL.Vertex(Point(start+dirs[dir]));
}
}
}
public void DrawCube(Vector3 corner, Vector3 dirA, Vector3 dirB, Vector3 dirC, Color c) {
GL.Color(c);
Vector3[] dirs = new Vector3[]{dirA,dirB,dirC};
for (int i=0; i<2; i++) {
for (int j=0; j<2; j++) {
for (int dir=0; dir<3; dir++) {
Vector3 start = corner + dirs[(dir+1)%3]*i + dirs[(dir+2)%3]*j;
GL.Vertex(Point(start));
GL.Vertex(Point(start+dirs[dir]));
}
}
}
}
}
public class DrawArea3D: DrawArea {
public Matrix4x4 matrix;
public DrawArea3D(Vector3 min, Vector3 max, Matrix4x4 matrix): base(min,max) {
this.matrix = matrix;
}
public override Vector3 Point(Vector3 p) {
return matrix.MultiplyPoint3x4(
Vector3.Scale(
new Vector3(
(p.x-canvasMin.x) / (canvasMax.x-canvasMin.x),
(p.y-canvasMin.y) / (canvasMax.y-canvasMin.y),
p.z
),
max-min
)+min
);
}
}
public class SmoothFollower {
private Vector3 targetPosition;
private Vector3 position;
private Vector3 velocity;
private float smoothingTime;
private float prediction;
public SmoothFollower(float smoothingTime) {
targetPosition = Vector3.zero;
position = Vector3.zero;
velocity = Vector3.zero;
this.smoothingTime = smoothingTime;
prediction = 1;
}
public SmoothFollower(float smoothingTime, float prediction) {
targetPosition = Vector3.zero;
position = Vector3.zero;
velocity = Vector3.zero;
this.smoothingTime = smoothingTime;
this.prediction = prediction;
}
// Update should be called once per frame
public Vector3 Update(Vector3 targetPositionNew, float deltaTime) {
Vector3 targetVelocity = (targetPositionNew-targetPosition)/deltaTime;
targetPosition = targetPositionNew;
float d = Mathf.Min(1,deltaTime/smoothingTime);
velocity = velocity*(1-d) + (targetPosition+targetVelocity*prediction-position)*d;
position += velocity*Time.deltaTime;
return position;
}
public Vector3 Update(Vector3 targetPositionNew, float deltaTime, bool reset) {
if (reset) {
targetPosition = targetPositionNew;
position = targetPositionNew;
velocity = Vector3.zero;
return position;
}
return Update(targetPositionNew, deltaTime);
}
public Vector3 GetPosition() { return position; }
public Vector3 GetVelocity() { return velocity; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment