├── CFrame and Vector3 ├── .vs │ └── CFrame and Vector3 │ │ └── v14 │ │ └── .suo ├── CFrame and Vector3.sln └── CFrame and Vector3 │ ├── App.config │ ├── CFrame and Vector3.csproj │ ├── CFrame.cs │ ├── Program.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── Vector3.cs │ ├── bin │ └── Debug │ │ ├── CFrame and Vector3.exe │ │ ├── CFrame and Vector3.exe.config │ │ ├── CFrame and Vector3.pdb │ │ ├── CFrame and Vector3.vshost.exe │ │ ├── CFrame and Vector3.vshost.exe.config │ │ └── CFrame and Vector3.vshost.exe.manifest │ └── obj │ └── Debug │ ├── CFrame and Vector3.csproj.FileListAbsolute.txt │ ├── CFrame and Vector3.csprojResolveAssemblyReference.cache │ ├── CFrame and Vector3.exe │ ├── CFrame and Vector3.pdb │ ├── DesignTimeResolveAssemblyReferencesInput.cache │ ├── TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs │ ├── TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs │ └── TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs ├── LICENSE ├── Lua ├── CFrame.lua └── Vector3.lua └── README.md /CFrame and Vector3/.vs/CFrame and Vector3/v14/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EgoMooseOldProjects/Vector3-and-CFrame/2a0716f773362afb5e16205e3f2d518b30af5099/CFrame and Vector3/.vs/CFrame and Vector3/v14/.suo -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CFrame and Vector3", "CFrame and Vector3\CFrame and Vector3.csproj", "{56D79B32-653F-4212-BE44-53163742CA7A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {56D79B32-653F-4212-BE44-53163742CA7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {56D79B32-653F-4212-BE44-53163742CA7A}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {56D79B32-653F-4212-BE44-53163742CA7A}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {56D79B32-653F-4212-BE44-53163742CA7A}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/CFrame and Vector3.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {56D79B32-653F-4212-BE44-53163742CA7A} 8 | Exe 9 | Properties 10 | CFrame_and_Vector3 11 | CFrame and Vector3 12 | v4.6.1 13 | 512 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 62 | -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/CFrame.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace CFrame_and_Vector3 8 | { 9 | class CFrame 10 | { 11 | private float m11 = 1, m12 = 0, m13 = 0, m14 = 0; 12 | private float m21 = 0, m22 = 1, m23 = 0, m24 = 0; 13 | private float m31 = 0, m32 = 0, m33 = 1, m34 = 0; 14 | private const float m41 = 0, m42 = 0, m43 = 0, m44 = 1; 15 | 16 | public readonly float x = 0, y = 0, z = 0; 17 | public readonly Vector3 p = new Vector3(0, 0, 0); 18 | public readonly Vector3 lookVector = new Vector3(0, 0, -1); 19 | public readonly Vector3 rightVector = new Vector3(1, 0, 0); 20 | public readonly Vector3 upVector = new Vector3(0, 1, 0); 21 | 22 | private static Vector3 RIGHT = new Vector3(1, 0, 0); 23 | private static Vector3 UP = new Vector3(0, 1, 0); 24 | private static Vector3 BACK = new Vector3(0, 0, 1); 25 | 26 | // constructors 27 | 28 | public CFrame(Vector3 pos) 29 | { 30 | m14 = pos.x; 31 | m24 = pos.y; 32 | m34 = pos.z; 33 | x = m14; y = m24; z = m34; 34 | p = new Vector3(m14, m24, m34); 35 | lookVector = new Vector3(-m13, -m23, -m33); 36 | rightVector = new Vector3(m11, m21, m31); 37 | upVector = new Vector3(m12, m22, m32); 38 | } 39 | 40 | public CFrame(Vector3 eye, Vector3 look) 41 | { 42 | Vector3 zAxis = (eye - look).unit; 43 | Vector3 xAxis = Vector3.Cross(UP, zAxis); 44 | Vector3 yAxis = Vector3.Cross(zAxis, xAxis); 45 | if (xAxis.magnitude == 0) 46 | { 47 | if (zAxis.y < 0) 48 | { 49 | xAxis = new Vector3(0, 0, -1); 50 | yAxis = new Vector3(1, 0, 0); 51 | zAxis = new Vector3(0, -1, 0); 52 | } 53 | else 54 | { 55 | xAxis = new Vector3(0, 0, 1); 56 | yAxis = new Vector3(1, 0, 0); 57 | zAxis = new Vector3(0, 1, 0); 58 | } 59 | } 60 | m11 = xAxis.x; m12 = yAxis.x; m13 = zAxis.x; m14 = eye.x; 61 | m21 = xAxis.y; m22 = yAxis.y; m23 = zAxis.y; m24 = eye.y; 62 | m31 = xAxis.z; m32 = yAxis.z; m33 = zAxis.z; m34 = eye.z; 63 | x = m14; y = m24; z = m34; 64 | p = new Vector3(m14, m24, m34); 65 | lookVector = new Vector3(-m13, -m23, -m33); 66 | rightVector = new Vector3(m11, m21, m31); 67 | upVector = new Vector3(m12, m22, m32); 68 | } 69 | 70 | public CFrame(float nx = 0, float ny = 0, float nz = 0) 71 | { 72 | m14 = nx; 73 | m24 = ny; 74 | m34 = nz; 75 | x = m14; y = m24; z = m34; 76 | p = new Vector3(m14, m24, m34); 77 | lookVector = new Vector3(-m13, -m23, -m33); 78 | rightVector = new Vector3(m11, m21, m31); 79 | upVector = new Vector3(m12, m22, m32); 80 | } 81 | 82 | public CFrame(float nx, float ny, float nz, float i, float j, float k, float w) 83 | { 84 | m14 = nx; 85 | m24 = ny; 86 | m34 = nz; 87 | m11 = 1 - 2 * (float)Math.Pow(j, 2) - 2 * (float)Math.Pow(k, 2); 88 | m12 = 2 * (i * j - k * w); 89 | m13 = 2 * (i * k + j * w); 90 | m21 = 2 * (i * j + k * w); 91 | m22 = 1 - 2 * (float)Math.Pow(i, 2) - 2 * (float)Math.Pow(k, 2); 92 | m23 = 2 * (j * k - i * w); 93 | m31 = 2 * (i * k - j * w); 94 | m32 = 2 * (j * k + i * w); 95 | m33 = 1 - 2 * (float)Math.Pow(i, 2) - 2 * (float)Math.Pow(j, 2); 96 | x = m14; y = m24; z = m34; 97 | p = new Vector3(m14, m24, m34); 98 | lookVector = new Vector3(-m13, -m23, -m33); 99 | rightVector = new Vector3(m11, m21, m31); 100 | upVector = new Vector3(m12, m22, m32); 101 | } 102 | 103 | public CFrame(float n14, float n24, float n34, float n11, float n12, float n13, float n21, float n22, float n23, float n31, float n32, float n33) 104 | { 105 | m14 = n14; m24 = n24; m34 = n34; 106 | m11 = n11; m12 = n12; m13 = n13; 107 | m21 = n21; m22 = n22; m23 = n23; 108 | m31 = n31; m32 = n32; m33 = n33; 109 | x = m14; y = m24; z = m34; 110 | p = new Vector3(m14, m24, m34); 111 | lookVector = new Vector3(-m13, -m23, -m33); 112 | rightVector = new Vector3(m11, m21, m31); 113 | upVector = new Vector3(m12, m22, m32); 114 | } 115 | 116 | // opperator overloads 117 | 118 | public static CFrame operator +(CFrame a, Vector3 b) 119 | { 120 | float[] ac = a.components(); 121 | float x = ac[0], y = ac[1], z = ac[2], m11 = ac[3], m12 = ac[4], m13 = ac[5], m21 = ac[6], m22 = ac[7], m23 = ac[8], m31 = ac[9], m32 = ac[10], m33 = ac[11]; 122 | return new CFrame(x + b.x, y + b.y, z + b.z, m11, m12, m13, m21, m22, m23, m31, m32, m33); 123 | } 124 | 125 | public static CFrame operator -(CFrame a, Vector3 b) 126 | { 127 | float[] ac = a.components(); 128 | float x = ac[0], y = ac[1], z = ac[2], m11 = ac[3], m12 = ac[4], m13 = ac[5], m21 = ac[6], m22 = ac[7], m23 = ac[8], m31 = ac[9], m32 = ac[10], m33 = ac[11]; 129 | return new CFrame(x - b.x, y - b.y, z - b.z, m11, m12, m13, m21, m22, m23, m31, m32, m33); 130 | } 131 | 132 | public static Vector3 operator *(CFrame a, Vector3 b) 133 | { 134 | float[] ac = a.components(); 135 | float x = ac[0], y = ac[1], z = ac[2], m11 = ac[3], m12 = ac[4], m13 = ac[5], m21 = ac[6], m22 = ac[7], m23 = ac[8], m31 = ac[9], m32 = ac[10], m33 = ac[11]; 136 | Vector3 right = new Vector3(m11, m21, m31); 137 | Vector3 up = new Vector3(m12, m22, m32); 138 | Vector3 back = new Vector3(m13, m23, m33); 139 | return a.p + b.x * right + b.y * up + b.z * back; 140 | } 141 | 142 | public static CFrame operator *(CFrame a, CFrame b) 143 | { 144 | float[] ac = a.components(); 145 | float[] bc = b.components(); 146 | float a14 = ac[0], a24 = ac[1], a34 = ac[2], a11 = ac[3], a12 = ac[4], a13 = ac[5], a21 = ac[6], a22 = ac[7], a23 = ac[8], a31 = ac[9], a32 = ac[10], a33 = ac[11]; 147 | float b14 = bc[0], b24 = bc[1], b34 = bc[2], b11 = bc[3], b12 = bc[4], b13 = bc[5], b21 = bc[6], b22 = bc[7], b23 = bc[8], b31 = bc[9], b32 = bc[10], b33 = bc[11]; 148 | float n11 = a11 * b11 + a12 * b21 + a13 * b31 + a14 * m41; 149 | float n12 = a11 * b12 + a12 * b22 + a13 * b32 + a14 * m42; 150 | float n13 = a11 * b13 + a12 * b23 + a13 * b33 + a14 * m43; 151 | float n14 = a11 * b14 + a12 * b24 + a13 * b34 + a14 * m44; 152 | float n21 = a21 * b11 + a22 * b21 + a23 * b31 + a24 * m41; 153 | float n22 = a21 * b12 + a22 * b22 + a23 * b32 + a24 * m42; 154 | float n23 = a21 * b13 + a22 * b23 + a23 * b33 + a24 * m43; 155 | float n24 = a21 * b14 + a22 * b24 + a23 * b34 + a24 * m44; 156 | float n31 = a31 * b11 + a32 * b21 + a33 * b31 + a34 * m41; 157 | float n32 = a31 * b12 + a32 * b22 + a33 * b32 + a34 * m42; 158 | float n33 = a31 * b13 + a32 * b23 + a33 * b33 + a34 * m43; 159 | float n34 = a31 * b14 + a32 * b24 + a33 * b34 + a34 * m44; 160 | float n41 = m41 * b11 + m42 * b21 + m43 * b31 + m44 * m41; 161 | float n42 = m41 * b12 + m42 * b22 + m43 * b32 + m44 * m42; 162 | float n43 = m41 * b13 + m42 * b23 + m43 * b33 + m44 * m43; 163 | float n44 = m41 * b14 + m42 * b24 + m43 * b34 + m44 * m44; 164 | return new CFrame(n14, n24, n34, n11, n12, n13, n21, n22, n23, n31, n32, n33); 165 | } 166 | 167 | public override string ToString() 168 | { 169 | return String.Join(", ", components()); 170 | } 171 | 172 | // private static functions 173 | 174 | private static Vector3 vectorAxisAngle(Vector3 n, Vector3 v, float t) 175 | { 176 | n = n.unit; 177 | return v * (float)Math.Cos(t) + Vector3.Dot(v, n) * n * (1 - (float)Math.Cos(t)) + Vector3.Cross(n, v) * (float)Math.Sin(t); 178 | } 179 | 180 | private static float getDeterminant(CFrame a) 181 | { 182 | float[] ac = a.components(); 183 | float a14 = ac[0], a24 = ac[1], a34 = ac[2], a11 = ac[3], a12 = ac[4], a13 = ac[5], a21 = ac[6], a22 = ac[7], a23 = ac[8], a31 = ac[9], a32 = ac[10], a33 = ac[11]; 184 | float det = (a11 * a22 * a33 * m44 + a11 * a23 * a34 * m42 + a11 * a24 * a32 * m43 185 | + a12 * a21 * a34 * m43 + a12 * a23 * a31 * m44 + a12 * a24 * a33 * m41 186 | + a13 * a21 * a32 * m44 + a13 * a22 * a34 * m41 + a13 * a24 * a31 * m42 187 | + a14 * a21 * a33 * m42 + a14 * a22 * a31 * m43 + a14 * a23 * a32 * m41 188 | - a11 * a22 * a34 * m43 - a11 * a23 * a32 * m44 - a11 * a24 * a33 * m42 189 | - a12 * a21 * a33 * m44 - a12 * a23 * a34 * m41 - a12 * a24 * a31 * m43 190 | - a13 * a21 * a34 * m42 - a13 * a22 * a31 * m44 - a13 * a24 * a32 * m41 191 | - a14 * a21 * a32 * m43 - a14 * a22 * a33 * m41 - a14 * a23 * a31 * m42); 192 | return det; 193 | } 194 | 195 | private static CFrame invert4x4(CFrame a) 196 | { 197 | float[] ac = a.components(); 198 | float a14 = ac[0], a24 = ac[1], a34 = ac[2], a11 = ac[3], a12 = ac[4], a13 = ac[5], a21 = ac[6], a22 = ac[7], a23 = ac[8], a31 = ac[9], a32 = ac[10], a33 = ac[11]; 199 | float det = getDeterminant(a); 200 | if (det == 0) { return a; } 201 | float b11 = (a22 * a33 * m44 + a23 * a34 * m42 + a24 * a32 * m43 - a22 * a34 * m43 - a23 * a32 * m44 - a24 * a33 * m42) / det; 202 | float b12 = (a12 * a34 * m43 + a13 * a32 * m44 + a14 * a33 * m42 - a12 * a33 * m44 - a13 * a34 * m42 - a14 * a32 * m43) / det; 203 | float b13 = (a12 * a23 * m44 + a13 * a24 * m42 + a14 * a22 * m43 - a12 * a24 * m43 - a13 * a22 * m44 - a14 * a23 * m42) / det; 204 | float b14 = (a12 * a24 * a33 + a13 * a22 * a34 + a14 * a23 * a32 - a12 * a23 * a34 - a13 * a24 * a32 - a14 * a22 * a33) / det; 205 | float b21 = (a21 * a34 * m43 + a23 * a31 * m44 + a24 * a33 * m41 - a21 * a33 * m44 - a23 * a34 * m41 - a24 * a31 * m43) / det; 206 | float b22 = (a11 * a33 * m44 + a13 * a34 * m41 + a14 * a31 * m43 - a11 * a34 * m43 - a13 * a31 * m44 - a14 * a33 * m41) / det; 207 | float b23 = (a11 * a24 * m43 + a13 * a21 * m44 + a14 * a23 * m41 - a11 * a23 * m44 - a13 * a24 * m41 - a14 * a21 * m43) / det; 208 | float b24 = (a11 * a23 * a34 + a13 * a24 * a31 + a14 * a21 * a33 - a11 * a24 * a33 - a13 * a21 * a34 - a14 * a23 * a31) / det; 209 | float b31 = (a21 * a32 * m44 + a22 * a34 * m41 + a24 * a31 * m42 - a21 * a34 * m42 - a22 * a31 * m44 - a24 * a32 * m41) / det; 210 | float b32 = (a11 * a34 * m42 + a12 * a31 * m44 + a14 * a32 * m41 - a11 * a32 * m44 - a12 * a34 * m41 - a14 * a31 * m42) / det; 211 | float b33 = (a11 * a22 * m44 + a12 * a24 * m41 + a14 * a21 * m42 - a11 * a24 * m42 - a12 * a21 * m44 - a14 * a22 * m41) / det; 212 | float b34 = (a11 * a24 * a32 + a12 * a21 * a34 + a14 * a22 * a31 - a11 * a22 * a34 - a12 * a24 * a31 - a14 * a21 * a32) / det; 213 | float b41 = (a21 * a33 * m42 + a22 * a31 * m43 + a23 * a32 * m41 - a21 * a32 * m43 - a22 * a33 * m41 - a23 * a31 * m42) / det; 214 | float b42 = (a11 * a32 * m43 + a12 * a33 * m41 + a13 * a31 * m42 - a11 * a33 * m42 - a12 * a31 * m43 - a13 * a32 * m41) / det; 215 | float b43 = (a11 * a23 * m42 + a12 * a21 * m43 + a13 * a22 * m41 - a11 * a22 * m43 - a12 * a23 * m41 - a13 * a21 * m42) / det; 216 | float b44 = (a11 * a22 * a33 + a12 * a23 * a31 + a13 * a21 * a32 - a11 * a23 * a32 - a12 * a21 * a33 - a13 * a22 * a31) / det; 217 | return new CFrame(b14, b24, b34, b11, b12, b13, b21, b22, b23, b31, b32, b33); 218 | } 219 | 220 | private static float[] quaternionFromCFrame(CFrame a) 221 | { 222 | float[] ac = a.components(); 223 | float mx = ac[0], my = ac[1], mz = ac[2], m11 = ac[3], m12 = ac[4], m13 = ac[5], m21 = ac[6], m22 = ac[7], m23 = ac[8], m31 = ac[9], m32 = ac[10], m33 = ac[11]; 224 | float trace = m11 + m22 + m33; 225 | float w = 1, i = 0, j = 0, k = 0; 226 | if (trace > 0) 227 | { 228 | float s = (float)Math.Sqrt(1 + trace); 229 | float r = 0.5f / s; 230 | w = s * 0.5f; i = (m32 - m23) * r; j = (m13 - m31) * r; k = (m21 - m12) * r; 231 | } 232 | else 233 | { 234 | float big = Math.Max(Math.Max(m11, m22), m33); 235 | if (big == m11) 236 | { 237 | float s = (float)Math.Sqrt(1 + m11 - m22 - m33); 238 | float r = 0.5f / s; 239 | w = (m32 - m23) * r; i = 0.5f * s; j = (m21 + m12) * r; k = (m13 + m31) * r; 240 | } 241 | else if (big == m22) 242 | { 243 | float s = (float)Math.Sqrt(1 - m11 + m22 - m33); 244 | float r = 0.5f / s; 245 | w = (m13 - m31) * r; i = (m21 + m12) * r; j = 0.5f * s; k = (m32 + m23) * r; 246 | } 247 | else if (big == m33) 248 | { 249 | float s = (float)Math.Sqrt(1 - m11 - m22 + m33); 250 | float r = 0.5f / s; 251 | w = (m21 - m12) * r; i = (m13 + m31) * r; j = (m32 + m23) * r; k = 0.5f * s; 252 | } 253 | } 254 | return new float[] { w, i, j, k }; 255 | } 256 | 257 | private static CFrame lerpinternal(CFrame a, CFrame b, float t) 258 | { 259 | CFrame cf = a.inverse() * b; 260 | float[] q = quaternionFromCFrame(cf); 261 | float w = q[0], i = q[1], j = q[2], k = q[3]; 262 | float theta = (float)Math.Acos(w) * 2; 263 | Vector3 v = new Vector3(i, j, k); 264 | Vector3 p = a.p.Lerp(b.p, t); 265 | if (theta != 0) 266 | { 267 | CFrame r = a * fromAxisAngle(v, theta * t); 268 | return (r - r.p) + p; 269 | } 270 | else 271 | { 272 | return (a - a.p) + p; 273 | } 274 | } 275 | 276 | // public static functions 277 | 278 | public static CFrame fromAxisAngle(Vector3 axis, float theta) 279 | { 280 | Vector3 r = vectorAxisAngle(axis, RIGHT, theta); 281 | Vector3 u = vectorAxisAngle(axis, UP, theta); 282 | Vector3 b = vectorAxisAngle(axis, BACK, theta); 283 | return new CFrame(0, 0, 0, r.x, u.x, b.x, r.y, u.y, b.y, r.z, u.z, b.z); 284 | } 285 | 286 | public static CFrame Angles(float x, float y, float z) 287 | { 288 | CFrame cfx = fromAxisAngle(RIGHT, x); 289 | CFrame cfy = fromAxisAngle(UP, y); 290 | CFrame cfz = fromAxisAngle(BACK, z); 291 | return cfx * cfy * cfz; 292 | } 293 | 294 | public static CFrame fromEulerAnglesXYZ(float x, float y, float z) 295 | { 296 | return Angles(x, y, z); 297 | } 298 | 299 | // methods 300 | 301 | public CFrame inverse() 302 | { 303 | return invert4x4(this); 304 | } 305 | 306 | public CFrame lerp(CFrame cf2, float t) 307 | { 308 | return lerpinternal(this, cf2, t); 309 | } 310 | 311 | public CFrame toWorldSpace(CFrame cf2) 312 | { 313 | return this * cf2; 314 | } 315 | 316 | public CFrame toObjectSpace(CFrame cf2) 317 | { 318 | return this.inverse() * cf2; 319 | } 320 | 321 | public Vector3 pointToWorldSpace(Vector3 v) 322 | { 323 | return this * v; 324 | } 325 | 326 | public Vector3 pointToObjectSpace(Vector3 v) 327 | { 328 | return this.inverse() * v; 329 | } 330 | 331 | public Vector3 vectorToWorldSpace(Vector3 v) 332 | { 333 | return (this - this.p) * v; 334 | } 335 | 336 | public Vector3 vectorToObjectSpace(Vector3 v) 337 | { 338 | return (this - this.p).inverse() * v; 339 | } 340 | 341 | public float[] components() 342 | { 343 | return new float[] { m14, m24, m34, m11, m12, m13, m21, m22, m23, m31, m32, m33 }; 344 | } 345 | 346 | public float[] toEulerAnglesXYZ() 347 | { 348 | float x = (float)Math.Atan2(-m23, m33); 349 | float y = (float)Math.Asin(m13); 350 | float z = (float)Math.Atan2(-m12, m11); 351 | return new float[] { x, y, z }; 352 | } 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace CFrame_and_Vector3 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | CFrame dcf = new CFrame(); 14 | CFrame cf1 = new CFrame(1, 2, 3) * CFrame.Angles((float)Math.PI / 3, (float)Math.PI / 6, 0); 15 | CFrame cf2 = new CFrame(-4, 5, 7.2f) * CFrame.Angles(0, (float)Math.PI / 7, -(float)Math.PI / 3); 16 | CFrame cf = cf1 * cf2; 17 | 18 | Vector3 v = new Vector3(10, -5, 6); 19 | Vector3 v2 = new Vector3(12.6602535f, -0.669872522f, -1.2320509f); 20 | 21 | Console.WriteLine(cf * cf2.inverse()); 22 | Console.WriteLine(cf1.pointToObjectSpace(v2)); 23 | Console.ReadLine(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("CFrame and Vector3")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("CFrame and Vector3")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("56d79b32-653f-4212-be44-53163742ca7a")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/Vector3.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace CFrame_and_Vector3 8 | { 9 | class Vector3 10 | { 11 | public readonly float x, y, z; 12 | public readonly float magnitude; 13 | public Vector3 unit { get { return normalize(this); } } 14 | 15 | public Vector3(float x = 0, float y = 0, float z = 0) 16 | { 17 | this.x = x; 18 | this.y = y; 19 | this.z = z; 20 | magnitude = calcMagnitude(this); 21 | } 22 | 23 | // opperator overloads 24 | 25 | public static Vector3 operator -(Vector3 v) 26 | { 27 | return new Vector3(-v.x, -v.y, -v.z); 28 | } 29 | 30 | public static Vector3 operator *(float k, Vector3 a) 31 | { 32 | return new Vector3(a.x * k, a.y * k, a.z * k); 33 | } 34 | 35 | public static Vector3 operator *(Vector3 a, float k) 36 | { 37 | return new Vector3(a.x * k, a.y * k, a.z * k); 38 | } 39 | 40 | public static Vector3 operator +(Vector3 a, Vector3 b) 41 | { 42 | return new Vector3(a.x + b.x, a.y + b.y, a.z + b.z); 43 | } 44 | 45 | public static Vector3 operator -(Vector3 a, Vector3 b) 46 | { 47 | return new Vector3(a.x - b.x, a.y - b.y, a.z - b.z); 48 | } 49 | 50 | public static Vector3 operator *(Vector3 a, Vector3 b) 51 | { 52 | return new Vector3(a.x * b.x, a.y * b.y, a.z * b.z); 53 | } 54 | 55 | public static Vector3 operator /(Vector3 a, Vector3 b) 56 | { 57 | return new Vector3(a.x / b.x, a.y / b.y, a.z / b.z); 58 | } 59 | 60 | public override string ToString() 61 | { 62 | return x + ", " + y + ", " + z; 63 | } 64 | 65 | // statics 66 | 67 | private static float calcMagnitude(Vector3 v) 68 | { 69 | return (float)Math.Sqrt(Dot(v, v)); 70 | } 71 | 72 | private static Vector3 normalize(Vector3 v) 73 | { 74 | float m = calcMagnitude(v); 75 | float nx = v.x / m, ny = v.y / m, nz = v.z / m; 76 | return new Vector3(nx, ny, nz); 77 | } 78 | 79 | public static float Dot(Vector3 a, Vector3 b) 80 | { 81 | return a.x*b.x + a.y*b.y + a.z*b.z; 82 | } 83 | 84 | public static Vector3 Cross(Vector3 a, Vector3 b) 85 | { 86 | return new Vector3( 87 | a.y * b.z - b.y * a.z, 88 | a.z * b.x - b.z * a.x, 89 | a.x * b.y - b.x * a.y 90 | ); 91 | } 92 | 93 | // methods 94 | 95 | public Vector3 Lerp(Vector3 b, float t) 96 | { 97 | return (1 - t) * this + t * b; 98 | } 99 | 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/bin/Debug/CFrame and Vector3.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EgoMooseOldProjects/Vector3-and-CFrame/2a0716f773362afb5e16205e3f2d518b30af5099/CFrame and Vector3/CFrame and Vector3/bin/Debug/CFrame and Vector3.exe -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/bin/Debug/CFrame and Vector3.exe.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/bin/Debug/CFrame and Vector3.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EgoMooseOldProjects/Vector3-and-CFrame/2a0716f773362afb5e16205e3f2d518b30af5099/CFrame and Vector3/CFrame and Vector3/bin/Debug/CFrame and Vector3.pdb -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/bin/Debug/CFrame and Vector3.vshost.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EgoMooseOldProjects/Vector3-and-CFrame/2a0716f773362afb5e16205e3f2d518b30af5099/CFrame and Vector3/CFrame and Vector3/bin/Debug/CFrame and Vector3.vshost.exe -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/bin/Debug/CFrame and Vector3.vshost.exe.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/bin/Debug/CFrame and Vector3.vshost.exe.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/obj/Debug/CFrame and Vector3.csproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | C:\Users\Michael\Documents\Visual Studio 2015\Projects\C# Projects\ConsoleApplications\CFrame and Vector3\CFrame and Vector3\bin\Debug\CFrame and Vector3.exe.config 2 | C:\Users\Michael\Documents\Visual Studio 2015\Projects\C# Projects\ConsoleApplications\CFrame and Vector3\CFrame and Vector3\bin\Debug\CFrame and Vector3.exe 3 | C:\Users\Michael\Documents\Visual Studio 2015\Projects\C# Projects\ConsoleApplications\CFrame and Vector3\CFrame and Vector3\bin\Debug\CFrame and Vector3.pdb 4 | C:\Users\Michael\Documents\Visual Studio 2015\Projects\C# Projects\ConsoleApplications\CFrame and Vector3\CFrame and Vector3\obj\Debug\CFrame and Vector3.csprojResolveAssemblyReference.cache 5 | C:\Users\Michael\Documents\Visual Studio 2015\Projects\C# Projects\ConsoleApplications\CFrame and Vector3\CFrame and Vector3\obj\Debug\CFrame and Vector3.exe 6 | C:\Users\Michael\Documents\Visual Studio 2015\Projects\C# Projects\ConsoleApplications\CFrame and Vector3\CFrame and Vector3\obj\Debug\CFrame and Vector3.pdb 7 | -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/obj/Debug/CFrame and Vector3.csprojResolveAssemblyReference.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EgoMooseOldProjects/Vector3-and-CFrame/2a0716f773362afb5e16205e3f2d518b30af5099/CFrame and Vector3/CFrame and Vector3/obj/Debug/CFrame and Vector3.csprojResolveAssemblyReference.cache -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/obj/Debug/CFrame and Vector3.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EgoMooseOldProjects/Vector3-and-CFrame/2a0716f773362afb5e16205e3f2d518b30af5099/CFrame and Vector3/CFrame and Vector3/obj/Debug/CFrame and Vector3.exe -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/obj/Debug/CFrame and Vector3.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EgoMooseOldProjects/Vector3-and-CFrame/2a0716f773362afb5e16205e3f2d518b30af5099/CFrame and Vector3/CFrame and Vector3/obj/Debug/CFrame and Vector3.pdb -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EgoMooseOldProjects/Vector3-and-CFrame/2a0716f773362afb5e16205e3f2d518b30af5099/CFrame and Vector3/CFrame and Vector3/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EgoMooseOldProjects/Vector3-and-CFrame/2a0716f773362afb5e16205e3f2d518b30af5099/CFrame and Vector3/CFrame and Vector3/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EgoMooseOldProjects/Vector3-and-CFrame/2a0716f773362afb5e16205e3f2d518b30af5099/CFrame and Vector3/CFrame and Vector3/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs -------------------------------------------------------------------------------- /CFrame and Vector3/CFrame and Vector3/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EgoMooseOldProjects/Vector3-and-CFrame/2a0716f773362afb5e16205e3f2d518b30af5099/CFrame and Vector3/CFrame and Vector3/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /Lua/CFrame.lua: -------------------------------------------------------------------------------- 1 | -- dependancies 2 | 3 | local Vector3 = require("vector3"); 4 | 5 | -- CFrame class 6 | 7 | local cframe = {__type = "cframe"}; 8 | local mt = {__index = cframe}; 9 | 10 | local prettyPrint = false; -- mainly for debug (not a feature in real CFrames) 11 | 12 | -- built-in functions 13 | 14 | local pi = math.pi; 15 | local max = math.max; 16 | local cos = math.cos; 17 | local sin = math.sin; 18 | local acos = math.acos; 19 | local asin = math.asin; 20 | local sqrt = math.sqrt; 21 | local atan2 = math.atan2; 22 | local unpack = unpack; 23 | local concat = table.concat; 24 | 25 | -- some variables 26 | 27 | local identityMatrix = { 28 | m11 = 1, m12 = 0, m13 = 0, 29 | m21 = 0, m22 = 1, m23 = 0, 30 | m31 = 0, m32 = 0, m33 = 1 31 | }; 32 | local m41, m42, m43, m44 = 0, 0, 0, 1; 33 | local identityCFrame = {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1}; 34 | 35 | local right = Vector3.new(1, 0, 0); 36 | local top = Vector3.new(0, 1, 0); 37 | local back = Vector3.new(0, 0, 1); 38 | 39 | -- private functions 40 | 41 | local function fromAxisAngle(axis, vector, theta) 42 | -- http://wiki.roblox.com/index.php?title=User:EgoMoose/Articles/Quaternions_and_slerping#Rodriguez_Rotation_formula:_Axis-angle_rotations 43 | local axis = axis.unit; 44 | return vector * cos(theta) + vector:Dot(axis) * axis * (1 - cos(theta)) + axis:Cross(vector) * sin(theta); 45 | end; 46 | 47 | local function cfTimesv3(cf, v3) 48 | local _, _, _, m11, m12, m13, m21, m22, m23, m31, m32, m33 = cf:components(); 49 | local right = Vector3.new(m11, m21, m31); 50 | local top = Vector3.new(m12, m22, m32); 51 | local back = Vector3.new(m13, m23, m33); 52 | return cf.p + v3.x * right + v3.y * top + v3.z * back; 53 | end; 54 | 55 | local function fourByfour(a, b) 56 | local a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43, a44 = unpack(a); 57 | local b11, b12, b13, b14, b21, b22, b23, b24, b31, b32, b33, b34, b41, b42, b43, b44 = unpack(b); 58 | -- 4x4 matrix multiplication 59 | local m11 = a11*b11 + a12*b21 + a13*b31 + a14*b41; 60 | local m12 = a11*b12 + a12*b22 + a13*b32 + a14*b42; 61 | local m13 = a11*b13 + a12*b23 + a13*b33 + a14*b43; 62 | local m14 = a11*b14 + a12*b24 + a13*b34 + a14*b44; 63 | local m21 = a21*b11 + a22*b21 + a23*b31 + a24*b41; 64 | local m22 = a21*b12 + a22*b22 + a23*b32 + a24*b42; 65 | local m23 = a21*b13 + a22*b23 + a23*b33 + a24*b43; 66 | local m24 = a21*b14 + a22*b24 + a23*b34 + a24*b44; 67 | local m31 = a31*b11 + a32*b21 + a33*b31 + a34*b41; 68 | local m32 = a31*b12 + a32*b22 + a33*b32 + a34*b42; 69 | local m33 = a31*b13 + a32*b23 + a33*b33 + a34*b43; 70 | local m34 = a31*b14 + a32*b24 + a33*b34 + a34*b44; 71 | local m41 = a41*b11 + a42*b21 + a43*b31 + a44*b41; 72 | local m42 = a41*b12 + a42*b22 + a43*b32 + a44*b42; 73 | local m43 = a41*b13 + a42*b23 + a43*b33 + a44*b43; 74 | local m44 = a41*b14 + a42*b24 + a43*b34 + a44*b44; 75 | -- return the components 76 | return m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44; 77 | end; 78 | 79 | local function cfTimescf(cf1, cf2) 80 | local a14, a24, a34, a11, a12, a13, a21, a22, a23, a31, a32, a33 = cf1:components(); 81 | local b14, b24, b34, b11, b12, b13, b21, b22, b23, b31, b32, b33 = cf2:components(); 82 | local m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44 = fourByfour({ 83 | a11, a12, a13, a14, 84 | a21, a22, a23, a24, 85 | a31, a32, a33, a34, 86 | m41, m42, m43, m44 87 | }, { 88 | b11, b12, b13, b14, 89 | b21, b22, b23, b24, 90 | b31, b32, b33, b34, 91 | m41, m42, m43, m44 92 | }); 93 | -- return the final CFrame 94 | return cframe.new(m14, m24, m34, m11, m12, m13, m21, m22, m23, m31, m32, m33); 95 | end; 96 | 97 | local function getDeterminant(cf) 98 | local a14, a24, a34, a11, a12, a13, a21, a22, a23, a31, a32, a33 = cf:components(); 99 | local m41, m42, m43, m44 = 0, 0, 0, 1; 100 | local det = a11*a22*a33*m44 + a11*a23*a34*m42 + a11*a24*a32*m43 101 | + a12*a21*a34*m43 + a12*a23*a31*m44 + a12*a24*a33*m41 102 | + a13*a21*a32*m44 + a13*a22*a34*m41 + a13*a24*a31*m42 103 | + a14*a21*a33*m42 + a14*a22*a31*m43 + a14*a23*a32*m41 104 | - a11*a22*a34*m43 - a11*a23*a32*m44 - a11*a24*a33*m42 105 | - a12*a21*a33*m44 - a12*a23*a34*m41 - a12*a24*a31*m43 106 | - a13*a21*a34*m42 - a13*a22*a31*m44 - a13*a24*a32*m41 107 | - a14*a21*a32*m43 - a14*a22*a33*m41 - a14*a23*a31*m42; 108 | return det; 109 | end; 110 | 111 | local function invert4x4(cf) 112 | -- this is linear algebra. We're inverting a 4x4 matrix 113 | -- see: http://www.cg.info.hiroshima-cu.ac.jp/~miyazaki/knowledge/teche23.html 114 | -- it is very possible that the built-in CFrame class does not use this method as computers tend to use elimination methods 115 | -- regardless, both functions should return the same answer 116 | local a14, a24, a34, a11, a12, a13, a21, a22, a23, a31, a32, a33 = cf:components(); 117 | local det = getDeterminant(cf); 118 | if (det == 0) then return cf; end; 119 | local b11 = (a22*a33*m44 + a23*a34*m42 + a24*a32*m43 - a22*a34*m43 - a23*a32*m44 - a24*a33*m42) / det; 120 | local b12 = (a12*a34*m43 + a13*a32*m44 + a14*a33*m42 - a12*a33*m44 - a13*a34*m42 - a14*a32*m43) / det; 121 | local b13 = (a12*a23*m44 + a13*a24*m42 + a14*a22*m43 - a12*a24*m43 - a13*a22*m44 - a14*a23*m42) / det; 122 | local b14 = (a12*a24*a33 + a13*a22*a34 + a14*a23*a32 - a12*a23*a34 - a13*a24*a32 - a14*a22*a33) / det; 123 | local b21 = (a21*a34*m43 + a23*a31*m44 + a24*a33*m41 - a21*a33*m44 - a23*a34*m41 - a24*a31*m43) / det; 124 | local b22 = (a11*a33*m44 + a13*a34*m41 + a14*a31*m43 - a11*a34*m43 - a13*a31*m44 - a14*a33*m41) / det; 125 | local b23 = (a11*a24*m43 + a13*a21*m44 + a14*a23*m41 - a11*a23*m44 - a13*a24*m41 - a14*a21*m43) / det; 126 | local b24 = (a11*a23*a34 + a13*a24*a31 + a14*a21*a33 - a11*a24*a33 - a13*a21*a34 - a14*a23*a31) / det; 127 | local b31 = (a21*a32*m44 + a22*a34*m41 + a24*a31*m42 - a21*a34*m42 - a22*a31*m44 - a24*a32*m41) / det; 128 | local b32 = (a11*a34*m42 + a12*a31*m44 + a14*a32*m41 - a11*a32*m44 - a12*a34*m41 - a14*a31*m42) / det; 129 | local b33 = (a11*a22*m44 + a12*a24*m41 + a14*a21*m42 - a11*a24*m42 - a12*a21*m44 - a14*a22*m41) / det; 130 | local b34 = (a11*a24*a32 + a12*a21*a34 + a14*a22*a31 - a11*a22*a34 - a12*a24*a31 - a14*a21*a32) / det; 131 | local b41 = (a21*a33*m42 + a22*a31*m43 + a23*a32*m41 - a21*a32*m43 - a22*a33*m41 - a23*a31*m42) / det; 132 | local b42 = (a11*a32*m43 + a12*a33*m41 + a13*a31*m42 - a11*a33*m42 - a12*a31*m43 - a13*a32*m41) / det; 133 | local b43 = (a11*a23*m42 + a12*a21*m43 + a13*a22*m41 - a11*a22*m43 - a12*a23*m41 - a13*a21*m42) / det; 134 | local b44 = (a11*a22*a33 + a12*a23*a31 + a13*a21*a32 - a11*a23*a32 - a12*a21*a33 - a13*a22*a31) / det; 135 | return cframe.new(b14, b24, b34, b11, b12, b13, b21, b22, b23, b31, b32, b33); 136 | end; 137 | 138 | local function quaternionToMatrix(i, j, k, w) 139 | local m11 = 1 - 2*j^2 - 2*k^2; 140 | local m12 = 2*(i*j - k*w); 141 | local m13 = 2*(i*k + j*w); 142 | local m21 = 2*(i*j + k*w); 143 | local m22 = 1 - 2*i^2 - 2*k^2; 144 | local m23 = 2*(j*k - i*w); 145 | local m31 = 2*(i*k - j*w); 146 | local m32 = 2*(j*k + i*w); 147 | local m33 = 1 - 2*i^2 - 2*j^2; 148 | return {0, 0, 0, m11, m12, m13, m21, m22, m23, m31, m32, m33}; 149 | end; 150 | 151 | local function quaternionFromCFrame(cf) 152 | -- taken from: http://wiki.roblox.com/index.php?title=Quaternions_for_rotation#Quaternion_from_a_Rotation_Matrix 153 | local mx, my, mz, m11, m12, m13, m21, m22, m23, m31, m32, m33 = cf:components(); 154 | local trace = m11 + m22 + m33; 155 | if (trace > 0) then 156 | local s = sqrt(1 + trace); 157 | local r = 0.5 / s; 158 | return s * 0.5, Vector3.new((m32 - m23) * r, (m13 - m31) * r, (m21 - m12) * r); 159 | else -- find the largest diagonal element 160 | local big = max(m11, m22, m33); 161 | if big == m11 then 162 | local s = sqrt(1 + m11 - m22 - m33); 163 | local r = 0.5 / s; 164 | return (m32 - m23) * r, Vector3.new(0.5 * s, (m21 + m12) * r, (m13 + m31) * r); 165 | elseif big == m22 then 166 | local s = sqrt(1 - m11 + m22 - m33); 167 | local r = 0.5 / s; 168 | return (m13 - m31) * r, Vector3.new((m21 + m12) * r, 0.5 * s, (m32 + m23) * r); 169 | elseif big == m33 then 170 | local s = sqrt(1 - m11 - m22 + m33); 171 | local r = 0.5 / s; 172 | return (m21 - m12) * r, Vector3.new((m13 + m31) * r, (m32 + m23) * r, 0.5 * s); 173 | end; 174 | end; 175 | end; 176 | 177 | local function lerp(a, b, t) 178 | -- I have no idea what the internal implemenation is 179 | -- get the difference in CFrames, convert to quaternion, convert to axis angle, slerp 180 | local cf = a:inverse() * b; 181 | local w, v = quaternionFromCFrame(cf); 182 | local theta = acos(w) * 2; 183 | local p = a.p:Lerp(b.p, t); 184 | if theta ~= 0 then 185 | local rot = a * cframe.fromAxisAngle(v, theta * t); 186 | local _, _, _, m11, m12, m13, m21, m22, m23, m31, m32, m33 = rot:components(); 187 | return cframe.new(p.x, p.y, p.z, m11, m12, m13, m21, m22, m23, m31, m32, m33); 188 | else 189 | local _, _, _, m11, m12, m13, m21, m22, m23, m31, m32, m33 = a:components(); 190 | return cframe.new(p.x, p.y, p.z, m11, m12, m13, m21, m22, m23, m31, m32, m33); 191 | end; 192 | end; 193 | 194 | -- meta-methods 195 | 196 | function mt.__index(cf, index) 197 | if (index == "x" or index == "y" or index == "z") then 198 | return rawget(cf, "proxy").p[index]; 199 | elseif (index == "p" or index == "lookVector") then 200 | return rawget(cf, "proxy")[index]; 201 | elseif cframe[index] then 202 | return cframe[index]; 203 | else 204 | error(index .. " is not a valid member of CFrame"); 205 | end; 206 | end; 207 | 208 | function mt.__newindex(v, index, value) 209 | error(index .. " cannot be assigned to"); 210 | end; 211 | 212 | function mt.__add(a, b) 213 | local aIsCFrame = type(a) == "table" and a.__type and a.__type == "cframe"; 214 | local bIsCFrame = type(b) == "table" and b.__type and b.__type == "cframe"; 215 | local bIsVector = type(b) == "table" and b.__type and b.__type == "vector3"; 216 | if (aIsCFrame and bIsVector) then 217 | local x, y, z, m11, m12, m13, m21, m22, m23, m31, m32, m33 = a:components(); 218 | return cframe.new(x + b.x, y + b.y, z + b.z, m11, m12, m13, m21, m22, m23, m31, m32, m33); 219 | elseif (bIsCFrame) then 220 | local t = type(a); 221 | local cust = t == "table" and a.__type or t; 222 | -- fun fact, you can't add two CFrames so I assume the error code is wrong on this internally ;) 223 | error("bad argument #2 to '?' (CFrame expected, got " .. cust .. ")"); 224 | elseif (aIsCFrame) then 225 | local t = type(b); 226 | local cust = t == "table" and b.__type or t; 227 | error("bad argument #2 to '?' (Vector3 expected, got " .. cust .. ")"); 228 | end; 229 | end; 230 | 231 | function mt.__sub(a, b) 232 | local aIsCFrame = type(a) == "table" and a.__type and a.__type == "cframe"; 233 | local bIsCFrame = type(b) == "table" and b.__type and b.__type == "cframe"; 234 | local bIsVector = type(b) == "table" and b.__type and b.__type == "vector3"; 235 | if (aIsCFrame and bIsVector) then 236 | local x, y, z, m11, m12, m13, m21, m22, m23, m31, m32, m33 = a:components(); 237 | return cframe.new(x - b.x, y - b.y, z - b.z, m11, m12, m13, m21, m22, m23, m31, m32, m33); 238 | elseif (bIsCFrame) then 239 | local t = type(a); 240 | local cust = t == "table" and a.__type or t; 241 | -- fun fact, you can't add two CFrames so I assume the error code is wrong on this internally ;) 242 | error("bad argument #2 to '?' (CFrame expected, got " .. cust .. ")"); 243 | elseif (aIsCFrame) then 244 | local t = type(b); 245 | local cust = t == "table" and b.__type or t; 246 | error("bad argument #2 to '?' (Vector3 expected, got " .. cust .. ")"); 247 | end; 248 | end; 249 | 250 | function mt.__mul(a, b) 251 | local aIsCFrame = type(a) == "table" and a.__type and a.__type == "cframe"; 252 | local bIsCFrame = type(b) == "table" and b.__type and b.__type == "cframe"; 253 | local aIsVector = type(a) == "table" and a.__type and a.__type == "vector3"; 254 | local bIsVector = type(b) == "table" and b.__type and b.__type == "vector3"; 255 | if (aIsCFrame and bIsVector) then 256 | return cfTimesv3(a, b); 257 | elseif (aIsCFrame and bIsCFrame) then 258 | return cfTimescf(a, b); 259 | elseif (aIsCFrame) then 260 | local t = type(a); 261 | local cust = t == "table" and a.__type or t; 262 | error("bad argument #2 to '?' (Vector3 expected, got " .. cust .. " )"); 263 | elseif (bIsCFrame) then 264 | local t = type(a); 265 | local cust = t == "table" and a.__type or t; 266 | error("bad argument #1 to '?' (CFrame expected, got " .. cust .. " )"); 267 | end; 268 | end; 269 | 270 | function mt.__tostring(t) 271 | local components = {t:components()}; 272 | if prettyPrint then 273 | local s = ""; 274 | for i = 1, 12 do 275 | s = s .. ((i > 1 and i % 3 == 1 and "\n") or "") .. components[i] .. (i < 12 and ", " or ""); 276 | end; 277 | return s; 278 | else 279 | return concat(components, ", "); 280 | end; 281 | end; 282 | 283 | mt.__metatable = false; 284 | 285 | -- public class 286 | 287 | function cframe.new(...) 288 | local self = {}; 289 | self.proxy = {}; 290 | 291 | self.proxy.p = Vector3.new(0, 0, 0); 292 | for k, v in next, identityMatrix do 293 | self.proxy[k] = v; 294 | end; 295 | 296 | -- most of this function is error handling from bad userinput 297 | 298 | local t = {...}; 299 | local length = #t; 300 | if length > 12 then 301 | error("Invalid number of arguments: " .. length); 302 | elseif (length == 1) then -- single vector3 case 303 | local v = t[1]; 304 | local isVector = type(v) == "table" and v.__type and v.__type == "vector3"; 305 | if (not isVector) then 306 | local t = type(v); 307 | local cust = t == "table" and v.__type or t; 308 | error("bad argument #1 to 'new' (Vector3 expected, got" .. cust .. ")"); 309 | end; 310 | 311 | -- make a copy to avoid user changing the original vector 312 | self.proxy.p = Vector3.new(v.x, v.y, v.z); 313 | elseif (length == 2) then -- two vector3 case, we much build a lookAt matrix 314 | local eye, look = t[1], t[2]; 315 | local eyeIsVector = type(eye) == "table" and eye.__type and eye.__type == "vector3"; 316 | local lookIsVector = type(look) == "table" and look.__type and look.__type == "vector3"; 317 | if (not eyeIsVector and not lookIsVector) then 318 | local t = type(eye); 319 | local cust = t == "table" and eye.__type or t; 320 | error("bad argument #1 to 'new' (Vector3 expected, got" .. cust .. ")"); 321 | end; 322 | 323 | local zaxis = (eye - look).unit; 324 | local xaxis = top:Cross(zaxis).unit; 325 | local yaxis = zaxis:Cross(xaxis).unit; 326 | if (xaxis.magnitude == 0) then -- edge cases 327 | if zaxis.y < 0 then 328 | xaxis = Vector3.new(0, 0, -1); 329 | yaxis = Vector3.new(1, 0, 0); 330 | zaxis = Vector3.new(0, -1, 0); 331 | else 332 | xaxis = Vector3.new(0, 0, 1); 333 | yaxis = Vector3.new(1, 0, 0); 334 | zaxis = Vector3.new(0, 1, 0); 335 | end; 336 | end; 337 | self.proxy.p = Vector3.new(eye.x, eye.y, eye.z); 338 | self.proxy.m11, self.proxy.m12, self.proxy.m13 = xaxis.x, yaxis.x, zaxis.x; 339 | self.proxy.m21, self.proxy.m22, self.proxy.m23 = xaxis.y, yaxis.y, zaxis.y; 340 | self.proxy.m31, self.proxy.m32, self.proxy.m33 = xaxis.z, yaxis.z, zaxis.z; 341 | elseif (length == 3) then -- x, y, z 342 | for i = 1, length do 343 | local t = type(t[i]); 344 | local cust = t == "table" and n.__type or t; 345 | if cust ~= "number" then error("bad argument #" .. i .. " to 'new' (Number expected, got " .. cust .. ")"); end; 346 | end; 347 | 348 | self.proxy.p = Vector3.new(t[1], t[2], t[3]); 349 | elseif (length == 7) then -- x, y, z, quaternion 350 | for i = 1, length do 351 | local t = type(t[i]); 352 | local cust = t == "table" and n.__type or t; 353 | if cust ~= "number" then error("bad argument #" .. i .. " to 'new' (Number expected, got " .. cust .. ")"); end; 354 | end; 355 | 356 | local m = quaternionToMatrix(t[4], t[5], t[6], t[7]); 357 | self.proxy.p = Vector3.new(t[1], t[2], t[3]); 358 | self.proxy.m11, self.proxy.m12, self.proxy.m13 = m[4], m[5], m[6]; 359 | self.proxy.m21, self.proxy.m22, self.proxy.m23 = m[7], m[8], m[9]; 360 | self.proxy.m31, self.proxy.m32, self.proxy.m33 = m[10], m[11], m[12]; 361 | elseif (length == 12) then -- all components provided 362 | for i = 1, length do 363 | local t = type(t[i]); 364 | local cust = t == "table" and n.__type or t; 365 | if cust ~= "number" then error("bad argument #" .. i .. " to 'new' (Number expected, got " .. cust .. ")"); end; 366 | end; 367 | 368 | self.proxy.p = Vector3.new(t[1], t[2], t[3]); 369 | self.proxy.m11, self.proxy.m12, self.proxy.m13 = t[4], t[5], t[6]; 370 | self.proxy.m21, self.proxy.m22, self.proxy.m23 = t[7], t[8], t[9]; 371 | self.proxy.m31, self.proxy.m32, self.proxy.m33 = t[10], t[11], t[12]; 372 | elseif length > 0 then -- more than zero components 373 | for i = 1, length do 374 | local t = type(t[i]); 375 | local cust = t == "table" and n.__type or t; 376 | if cust ~= "number" then error("bad argument #" .. i .. " to 'new' (Number expected, got " .. cust .. ")"); end; 377 | end; 378 | error("bad argument #" .. (length + 1) .. " to 'new' (Number expected, got nil)"); 379 | end; 380 | 381 | self.proxy.lookVector = Vector3.new(-self.proxy.m13, -self.proxy.m23, -self.proxy.m33); 382 | 383 | return setmetatable(self, mt); 384 | end; 385 | 386 | function cframe.fromAxisAngle(axis, theta) 387 | local axis = axis.unit; 388 | local r = fromAxisAngle(axis, right, theta); 389 | local t = fromAxisAngle(axis, top, theta); 390 | local b = fromAxisAngle(axis, back, theta); 391 | return cframe.new( 392 | 0, 0, 0, 393 | r.x, t.x, b.x, 394 | r.y, t.y, b.y, 395 | r.z, t.z, b.z 396 | ); 397 | end; 398 | 399 | function cframe.Angles(x, y, z) 400 | -- two implemenations possible. The commented one is what is what is used in the real CFrame constructor (to my knowledge) 401 | -- the uncommented implemenation is easier for me to keep track of and I think makes more sense, but you can use either 402 | 403 | -- the method (presumably) used in the real constructor 404 | -- How to find this matrix: http://i.imgur.com/IWDMw0m.png 405 | -- https://en.wikipedia.org/wiki/Rotation_matrix#In_three_dimensions 406 | --[[ 407 | local m11 = cos(y) * cos(z); 408 | local m12 = -cos(y) * sin(z); 409 | local m13 = sin(y); 410 | local m21 = cos(z) * sin(x) * sin(y) + cos(x) * sin(z); 411 | local m22 = cos(x) * cos(z) - sin(x) * sin(y) * sin(z); 412 | local m23 = -cos(y) * sin(x); 413 | local m31 = sin(x) * sin(z) - cos(x) * cos(z) * sin(y); 414 | local m32 = cos(z) * sin(x) + cos(x) * sin(y) * sin(z); 415 | local m33 = cos(x) * cos(y); 416 | 417 | return cframe.new(0, 0, 0, m11, m12, m13, m21, m22, m23, m31, m32, m33); 418 | --]] 419 | 420 | -- the method I prefer 421 | local cfx = cframe.fromAxisAngle(right, x); 422 | local cfy = cframe.fromAxisAngle(top, y); 423 | local cfz = cframe.fromAxisAngle(back, z); 424 | 425 | return cfx * cfy * cfz; 426 | end; 427 | 428 | function cframe.fromEulerAnglesXYZ(x, y, z) 429 | return cframe.Angles(x, y, z); 430 | end; 431 | 432 | function cframe:inverse() 433 | return invert4x4(self); 434 | end; 435 | 436 | function cframe:lerp(self2, t) 437 | return lerp(self, self2, t); 438 | end; 439 | 440 | function cframe:toWorldSpace(self2) 441 | return self * self2; 442 | end; 443 | 444 | function cframe:toWorldSpace(self2) 445 | return self * self2; 446 | end; 447 | 448 | function cframe:toObjectSpace(self2) 449 | return self:inverse() * self2; 450 | end; 451 | 452 | function cframe:pointToWorldSpace(v3) 453 | return self * v3; 454 | end; 455 | 456 | function cframe:pointToObjectSpace(v3) 457 | return self:inverse() * v3; 458 | end; 459 | 460 | function cframe:vectorToWorldSpace(v3) 461 | return (self - self.p) * v3; 462 | end; 463 | 464 | function cframe:vectorToObjectSpace(v3) 465 | return (self - self.p):inverse() * v3; 466 | end; 467 | 468 | function cframe:components() 469 | local m = rawget(self, "proxy"); 470 | return m.p.x, m.p.y, m.p.z, m.m11, m.m12, m.m13, m.m21, m.m22, m.m23, m.m31, m.m32, m.m33; 471 | end; 472 | 473 | function cframe:toEulerAnglesXYZ() 474 | -- based off the method (presumably) used in the real constructor for cframe.Angles 475 | local _, _, _, m11, m12, m13, m21, m22, m23, m31, m32, m33 = self:components(); 476 | local x = atan2(-m23, m33); 477 | local y = asin(m13); 478 | local z = atan2(-m12, m11); 479 | return x, y, z; 480 | end; 481 | 482 | return cframe; -------------------------------------------------------------------------------- /Lua/Vector3.lua: -------------------------------------------------------------------------------- 1 | -- Vector3 class 2 | 3 | local vector3 = {__type = "vector3"}; 4 | local mt = {__index = vector3}; 5 | 6 | -- built-in functions 7 | 8 | local sqrt = math.sqrt; 9 | local acos = math.acos; 10 | local cos = math.cos; 11 | local sin = math.sin; 12 | 13 | -- private functions 14 | 15 | local function calcMagnitude(v) 16 | return sqrt(v.x^2 + v.y^2 + v.z^2); 17 | end; 18 | 19 | local function normalize(v) 20 | local magnitude = sqrt(v.x^2 + v.y^2 + v.z^2); 21 | if magnitude > 0 then 22 | return vector3.new(v.x / magnitude, v.y / magnitude, v.z / magnitude); 23 | else 24 | -- avoid 'nan' case 25 | return vector3.new(0, 0, 0); 26 | end; 27 | end; 28 | 29 | -- meta-methods 30 | 31 | function mt.__index(v, index) 32 | if (index == "unit") then 33 | return normalize(v); 34 | elseif (index == "magnitude") then 35 | return calcMagnitude(v); 36 | elseif vector3[index] then 37 | return vector3[index]; 38 | elseif rawget(v, "proxy")[index] then 39 | return rawget(v, "proxy")[index]; 40 | else 41 | error(index .. " is not a valid member of Vector3"); 42 | end; 43 | end; 44 | 45 | function mt.__newindex(v, index, value) 46 | error(index .. " cannot be assigned to"); 47 | end; 48 | 49 | function mt.__add(a, b) 50 | local aIsVector = type(a) == "table" and a.__type and a.__type == "vector3"; 51 | local bIsVector = type(b) == "table" and b.__type and b.__type == "vector3"; 52 | if (aIsVector and bIsVector) then 53 | return vector3.new(a.x + b.x, a.y + b.y, a.z + b.z); 54 | elseif (bIsVector) then 55 | -- check for custom type 56 | local t = type(a); 57 | local cust = t == "table" and a.__type or t; 58 | error("bad argument #1 to '?' (Vector3 expected, got " .. cust .. ")"); 59 | elseif (aIsVector) then 60 | local t = type(b); 61 | local cust = t == "table" and b.__type or t; 62 | error("bad argument #2 to '?' (Vector3 expected, got " .. cust .. ")"); 63 | end; 64 | end; 65 | 66 | function mt.__sub(a, b) 67 | local aIsVector = type(a) == "table" and a.__type and a.__type == "vector3"; 68 | local bIsVector = type(b) == "table" and b.__type and b.__type == "vector3"; 69 | if (aIsVector and bIsVector) then 70 | return vector3.new(a.x - b.x, a.y - b.y, a.z - b.z); 71 | elseif (bIsVector) then 72 | -- check for custom type 73 | local t = type(a); 74 | local cust = t == "table" and a.__type or t; 75 | error("bad argument #1 to '?' (Vector3 expected, got " .. cust .. ")"); 76 | elseif (aIsVector) then 77 | local t = type(b); 78 | local cust = t == "table" and b.__type or t; 79 | error("bad argument #2 to '?' (Vector3 expected, got " .. cust .. ")"); 80 | end; 81 | end; 82 | 83 | function mt.__mul(a, b) 84 | if (type(a) == "number") then 85 | return vector3.new(a * b.x, a * b.y, a * b.z); 86 | elseif (type(b) == "number") then 87 | return vector3.new(a.x * b, a.y * b, a.z * b); 88 | elseif (a.__type and a.__type == "vector3" and b.__type and b.__type == "vector3") then 89 | return vector3.new(a.x * b.x, a.y * b.y, a.z * b.z); 90 | else 91 | error("attempt to multiply a Vector3 with an incompatible value type or nil"); 92 | end; 93 | end; 94 | 95 | function mt.__div(a, b) 96 | if (type(a) == "number") then 97 | return vector3.new(a / b.x, a / b.y, a / b.z); 98 | elseif (type(b) == "number") then 99 | return vector3.new(a.x / b, a.y / b, a.z / b); 100 | elseif (a.__type and a.__type == "vector3" and b.__type and b.__type == "vector3") then 101 | return vector3.new(a.x / b.x, a.y / b.y, a.z / b.z); 102 | else 103 | error("attempt to divide a Vector3 with an incompatible value type or nil"); 104 | end; 105 | end; 106 | 107 | function mt.__unm(v) 108 | return vector3.new(-v.x, -v.y, -v.z); 109 | end; 110 | 111 | function mt.__tostring(v) 112 | return v.x .. ", " .. v.y .. ", " .. v.z; 113 | end; 114 | 115 | mt.__metatable = false; 116 | 117 | -- public class 118 | 119 | function vector3.new(x, y, z) 120 | local self = {}; 121 | self.proxy = {}; 122 | self.proxy.x = x or 0; 123 | self.proxy.y = y or 0; 124 | self.proxy.z = z or 0; 125 | return setmetatable(self, mt); 126 | end; 127 | 128 | function vector3.FromNormalId(id) 129 | pcall(function() id = id.Value or id end); 130 | if (id == 0) then -- right 131 | return vector3.new(1, 0, 0); 132 | elseif (id == 1) then -- top 133 | return vector3.new(0, 1, 0); 134 | elseif (id == 2) then -- back 135 | return vector3.new(0, 0, 1); 136 | elseif (id == 3) then -- left 137 | return vector3.new(-1, 0, 0); 138 | elseif (id == 4) then 139 | return vector3.new(0, -1, 0); 140 | elseif (id == 5) then 141 | return vector3.new(0, 0, -1); 142 | end; 143 | end; 144 | 145 | function vector3.FromAxis(id) 146 | pcall(function() id = id.Value or id end); 147 | if (id == 0) then -- right 148 | return vector3.new(1, 0, 0); 149 | elseif (id == 1) then -- top 150 | return vector3.new(0, 1, 0); 151 | elseif (id == 2) then -- back 152 | return vector3.new(0, 0, 1); 153 | end; 154 | end; 155 | 156 | function vector3:Lerp(v3, t) 157 | return self + (v3 - self) * t; 158 | end; 159 | 160 | function vector3:Dot(v3) 161 | local isVector = v3.__type and v3.__type == "vector3"; 162 | if (isVector) then 163 | return self.x * v3.x + self.y * v3.y + self.z * v3.z; 164 | else 165 | error("bad argument #1 to 'Dot' (Vector3 expected, got number)"); 166 | end; 167 | end; 168 | 169 | function vector3:Cross(v3) 170 | local isVector = v3.__type and v3.__type == "vector3"; 171 | if (isVector) then 172 | return vector3.new( 173 | self.y * v3.z - self.z * v3.y, 174 | self.z * v3.x - self.x * v3.z, 175 | self.x * v3.y - self.y * v3.x 176 | ); 177 | else 178 | error("bad argument #1 to 'Cross' (Vector3 expected, got number)"); 179 | end; 180 | end; 181 | 182 | return vector3; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vector3-and-CFrame-pure-Lua 2 | Vector3 and CFrame classes in pure Lua (also C# now!) 3 | 4 | These are a few "classes" (I use the term lightly) that I wrote for use in pure Lua. They are useful for anything 3D in gamedev or potentially mathematical. The CFrame class is used to store 3D positional/rotational data while the Vector3 class can be used in a similar fasion or for general mathematical usage. 5 | 6 | The Vector3 class is independant and can run on its own in plain old Lua. The CFrame class needs the Vector3 class to run. 7 | 8 | I originally posted this on my wiki page, but I wanted to have a copy on github in case it ever got deleted or whatever. 9 | http://wiki.roblox.com/index.php?title=User:EgoMoose/Articles/Pure_Lua_Vector3_and_CFrame 10 | --------------------------------------------------------------------------------