Quaternion_Tips.lua 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888
  1. --------------------------------------------------------------------------------
  2. -- Copyright (c) 2015 , 蒙占志(topameng) topameng@gmail.com
  3. -- All rights reserved.
  4. -- Use, modification and distribution are subject to the "MIT License"
  5. --------------------------------------------------------------------------------
  6. -- added by wsh @ 2017-12-28
  7. -- 注意:
  8. -- 1、已经被修改,别从tolua轻易替换来做升级
  9. local math = math
  10. local sin = math.sin
  11. local cos = math.cos
  12. local acos = math.acos
  13. local asin = math.asin
  14. local sqrt = math.sqrt
  15. local min = math.min
  16. local max = math.max
  17. local sign = math.sign
  18. local atan2 = Mathf.Atan2
  19. local clamp = Mathf.Clamp
  20. local abs = math.abs
  21. local setmetatable = setmetatable
  22. local getmetatable = getmetatable
  23. local rawget = rawget
  24. local rawset = rawset
  25. local rad2Deg = Mathf.Rad2Deg
  26. local halfDegToRad = 0.5 * Mathf.Deg2Rad
  27. local _next = { 2, 3, 1 }
  28. ---@class Quaternion
  29. ---@field identity Quaternion
  30. Quaternion = {}
  31. local _getter = {}
  32. local unity_quaternion = CS.UnityEngine.Quaternion
  33. local rotTemp ={{},{},{}}
  34. ---@type Vector3
  35. local rightTemp = nil
  36. ---@type Vector3
  37. local upTemp = nil
  38. Quaternion.isValueType = true
  39. Quaternion.__index = function(t, k)
  40. local var = rawget(Quaternion, k)
  41. if var ~= nil then
  42. return var
  43. end
  44. var = rawget(_getter, k)
  45. if var ~= nil then
  46. return var(t)
  47. end
  48. return rawget(unity_quaternion, k)
  49. end
  50. Quaternion.__newindex = function(t, name, k)
  51. if name == "eulerAngles" then
  52. t:SetEuler(k)
  53. else
  54. rawset(t, name, k)
  55. end
  56. end
  57. function Quaternion.New(x, y, z, w)
  58. local t = {x = x or 0, y = y or 0, z = z or 0, w = w or 0}
  59. setmetatable(t, Quaternion)
  60. return t
  61. end
  62. local _new = Quaternion.New
  63. Quaternion.__call = function(t, x, y, z, w)
  64. local t = {x = x or 0, y = y or 0, z = z or 0, w = w or 0}
  65. setmetatable(t, Quaternion)
  66. return t
  67. end
  68. function Quaternion:Set(x,y,z,w)
  69. self.x = x or 0
  70. self.y = y or 0
  71. self.z = z or 0
  72. self.w = w or 0
  73. end
  74. function Quaternion:Clone()
  75. return _new(self.x, self.y, self.z, self.w)
  76. end
  77. function Quaternion:Get()
  78. return self.x, self.y, self.z, self.w
  79. end
  80. function Quaternion.Dot(a, b)
  81. return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w
  82. end
  83. function Quaternion.Angle(a, b)
  84. local dot = Quaternion.Dot(a, b)
  85. if dot < 0 then dot = -dot end
  86. return acos(min(dot, 1)) * 2 * 57.29578
  87. end
  88. function Quaternion.AngleAxis(angle, axis)
  89. local normAxis = axis:Normalize()
  90. angle = angle * halfDegToRad
  91. local s = sin(angle)
  92. local w = cos(angle)
  93. local x = normAxis.x * s
  94. local y = normAxis.y * s
  95. local z = normAxis.z * s
  96. return _new(x,y,z,w)
  97. end
  98. ---@param axis Vector3
  99. function Quaternion:AngleAxisNonAlloc(angle, axis)
  100. local normAxi_x,normAxi_y,normAxi_z = axis:GetNormalizeXYZ()
  101. angle = angle * halfDegToRad
  102. local s = sin(angle)
  103. local w = cos(angle)
  104. local x = normAxi_x * s
  105. local y = normAxi_y * s
  106. local z = normAxi_z * s
  107. self:Set(x,y,z,w)
  108. end
  109. function Quaternion.Equals(a, b)
  110. return a.x == b.x and a.y == b.y and a.z == b.z and a.w == b.w
  111. end
  112. function Quaternion.Euler(x, y, z)
  113. x = x * 0.0087266462599716
  114. y = y * 0.0087266462599716
  115. z = z * 0.0087266462599716
  116. local sinX = sin(x)
  117. x = cos(x)
  118. local sinY = sin(y)
  119. y = cos(y)
  120. local sinZ = sin(z)
  121. z = cos(z)
  122. local q = {x = y * sinX * z + sinY * x * sinZ, y = sinY * x * z - y * sinX * sinZ, z = y * x * sinZ - sinY * sinX * z, w = y * x * z + sinY * sinX * sinZ}
  123. setmetatable(q, Quaternion)
  124. return q
  125. end
  126. function Quaternion:EulerNonAlloc(x, y, z)
  127. x = x * 0.0087266462599716
  128. y = y * 0.0087266462599716
  129. z = z * 0.0087266462599716
  130. local sinX = sin(x)
  131. x = cos(x)
  132. local sinY = sin(y)
  133. y = cos(y)
  134. local sinZ = sin(z)
  135. z = cos(z)
  136. self:Set(y * sinX * z + sinY * x * sinZ, sinY * x * z - y * sinX * sinZ, y * x * sinZ - sinY * sinX * z, y * x * z + sinY * sinX * sinZ)
  137. end
  138. function Quaternion:SetEuler(x, y, z)
  139. if y == nil and z == nil then
  140. y = x.y
  141. z = x.z
  142. x = x.x
  143. end
  144. x = x * 0.0087266462599716
  145. y = y * 0.0087266462599716
  146. z = z * 0.0087266462599716
  147. local sinX = sin(x)
  148. local cosX = cos(x)
  149. local sinY = sin(y)
  150. local cosY = cos(y)
  151. local sinZ = sin(z)
  152. local cosZ = cos(z)
  153. self.w = cosY * cosX * cosZ + sinY * sinX * sinZ
  154. self.x = cosY * sinX * cosZ + sinY * cosX * sinZ
  155. self.y = sinY * cosX * cosZ - cosY * sinX * sinZ
  156. self.z = cosY * cosX * sinZ - sinY * sinX * cosZ
  157. return self
  158. end
  159. function Quaternion:Normalize()
  160. local quat = self:Clone()
  161. quat:SetNormalize()
  162. return quat
  163. end
  164. function Quaternion:NormalizeNonAlloc()
  165. self:SetNormalize()
  166. end
  167. function Quaternion:SetNormalize()
  168. local n = self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w
  169. if n ~= 1 and n > 0 then
  170. n = 1 / sqrt(n)
  171. self.x = self.x * n
  172. self.y = self.y * n
  173. self.z = self.z * n
  174. self.w = self.w * n
  175. end
  176. end
  177. --产生一个新的从from到to的四元数
  178. function Quaternion.FromToRotation(from, to)
  179. local quat = Quaternion.New()
  180. quat:SetFromToRotation(from, to)
  181. return quat
  182. end
  183. function Quaternion:FromToRotationNonAlloc(from, to)
  184. self:SetFromToRotationNonAlloc(from, to)
  185. end
  186. --设置当前四元数为 from 到 to的旋转, 注意from和to同 forward平行会同unity不一致
  187. function Quaternion:SetFromToRotation1(from, to)
  188. local v0 = from:Normalize()
  189. local v1 = to:Normalize()
  190. local d = Vector3.Dot(v0, v1)
  191. if d > -1 + 1e-6 then
  192. local s = sqrt((1+d) * 2)
  193. local invs = 1 / s
  194. local c = Vector3.Cross(v0, v1) * invs
  195. self:Set(c.x, c.y, c.z, s * 0.5)
  196. elseif d > 1 - 1e-6 then
  197. return _new(0, 0, 0, 1)
  198. else
  199. local axis = Vector3.Cross(Vector3.right, v0)
  200. if axis:SqrMagnitude() < 1e-6 then
  201. axis = Vector3.Cross(Vector3.forward, v0)
  202. end
  203. self:Set(axis.x, axis.y, axis.z, 0)
  204. return self
  205. end
  206. return self
  207. end
  208. local function MatrixToQuaternion(rot, quat)
  209. local trace = rot[1][1] + rot[2][2] + rot[3][3]
  210. if trace > 0 then
  211. local s = sqrt(trace + 1)
  212. quat.w = 0.5 * s
  213. s = 0.5 / s
  214. quat.x = (rot[3][2] - rot[2][3]) * s
  215. quat.y = (rot[1][3] - rot[3][1]) * s
  216. quat.z = (rot[2][1] - rot[1][2]) * s
  217. quat:SetNormalize()
  218. else
  219. local i = 1
  220. local q = {0, 0, 0}
  221. if rot[2][2] > rot[1][1] then
  222. i = 2
  223. end
  224. if rot[3][3] > rot[i][i] then
  225. i = 3
  226. end
  227. local j = _next[i]
  228. local k = _next[j]
  229. local t = rot[i][i] - rot[j][j] - rot[k][k] + 1
  230. local s = 0.5 / sqrt(t)
  231. q[i] = s * t
  232. local w = (rot[k][j] - rot[j][k]) * s
  233. q[j] = (rot[j][i] + rot[i][j]) * s
  234. q[k] = (rot[k][i] + rot[i][k]) * s
  235. quat:Set(q[1], q[2], q[3], w)
  236. quat:SetNormalize()
  237. end
  238. end
  239. ---@param from Quaternion
  240. ---@param to Quaternion
  241. function Quaternion:SetFromToRotation(from, to)
  242. from = from:Normalize()
  243. to = to:Normalize()
  244. local e = Vector3.Dot(from, to)
  245. if e > 1 - 1e-6 then
  246. self:Set(0, 0, 0, 1)
  247. elseif e < -1 + 1e-6 then
  248. local left = {0, from.z, from.y}
  249. local mag = left[2] * left[2] + left[3] * left[3] --+ left[1] * left[1] = 0
  250. if mag < 1e-6 then
  251. left[1] = -from.z
  252. left[2] = 0
  253. left[3] = from.x
  254. mag = left[1] * left[1] + left[3] * left[3]
  255. end
  256. local invlen = 1/sqrt(mag)
  257. left[1] = left[1] * invlen
  258. left[2] = left[2] * invlen
  259. left[3] = left[3] * invlen
  260. local up = {0, 0, 0}
  261. up[1] = left[2] * from.z - left[3] * from.y
  262. up[2] = left[3] * from.x - left[1] * from.z
  263. up[3] = left[1] * from.y - left[2] * from.x
  264. local fxx = -from.x * from.x
  265. local fyy = -from.y * from.y
  266. local fzz = -from.z * from.z
  267. local fxy = -from.x * from.y
  268. local fxz = -from.x * from.z
  269. local fyz = -from.y * from.z
  270. local uxx = up[1] * up[1]
  271. local uyy = up[2] * up[2]
  272. local uzz = up[3] * up[3]
  273. local uxy = up[1] * up[2]
  274. local uxz = up[1] * up[3]
  275. local uyz = up[2] * up[3]
  276. local lxx = -left[1] * left[1]
  277. local lyy = -left[2] * left[2]
  278. local lzz = -left[3] * left[3]
  279. local lxy = -left[1] * left[2]
  280. local lxz = -left[1] * left[3]
  281. local lyz = -left[2] * left[3]
  282. local rot =
  283. {
  284. {fxx + uxx + lxx, fxy + uxy + lxy, fxz + uxz + lxz},
  285. {fxy + uxy + lxy, fyy + uyy + lyy, fyz + uyz + lyz},
  286. {fxz + uxz + lxz, fyz + uyz + lyz, fzz + uzz + lzz},
  287. }
  288. MatrixToQuaternion(rot, self)
  289. else
  290. local v = Vector3.Cross(from, to)
  291. local h = (1 - e) / Vector3.Dot(v, v)
  292. local hx = h * v.x
  293. local hz = h * v.z
  294. local hxy = hx * v.y
  295. local hxz = hx * v.z
  296. local hyz = hz * v.y
  297. local rot =
  298. {
  299. {e + hx*v.x, hxy - v.z, hxz + v.y},
  300. {hxy + v.z, e + h*v.y*v.y, hyz-v.x},
  301. {hxz - v.y, hyz + v.x, e + hz*v.z},
  302. }
  303. MatrixToQuaternion(rot, self)
  304. end
  305. end
  306. ---@param from Quaternion
  307. ---@param to Quaternion
  308. function Quaternion:SetFromToRotationNonAlloc(from, to)
  309. from = from:NormalizeNonAlloc()
  310. to = to:NormalizeNonAlloc()
  311. local e = Vector3.Dot(from, to)
  312. if e > 1 - 1e-6 then
  313. self:Set(0, 0, 0, 1)
  314. elseif e < -1 + 1e-6 then
  315. local left = {0, from.z, from.y}
  316. local mag = left[2] * left[2] + left[3] * left[3] --+ left[1] * left[1] = 0
  317. if mag < 1e-6 then
  318. left[1] = -from.z
  319. left[2] = 0
  320. left[3] = from.x
  321. mag = left[1] * left[1] + left[3] * left[3]
  322. end
  323. local invlen = 1/sqrt(mag)
  324. left[1] = left[1] * invlen
  325. left[2] = left[2] * invlen
  326. left[3] = left[3] * invlen
  327. local up = {0, 0, 0}
  328. up[1] = left[2] * from.z - left[3] * from.y
  329. up[2] = left[3] * from.x - left[1] * from.z
  330. up[3] = left[1] * from.y - left[2] * from.x
  331. local fxx = -from.x * from.x
  332. local fyy = -from.y * from.y
  333. local fzz = -from.z * from.z
  334. local fxy = -from.x * from.y
  335. local fxz = -from.x * from.z
  336. local fyz = -from.y * from.z
  337. local uxx = up[1] * up[1]
  338. local uyy = up[2] * up[2]
  339. local uzz = up[3] * up[3]
  340. local uxy = up[1] * up[2]
  341. local uxz = up[1] * up[3]
  342. local uyz = up[2] * up[3]
  343. local lxx = -left[1] * left[1]
  344. local lyy = -left[2] * left[2]
  345. local lzz = -left[3] * left[3]
  346. local lxy = -left[1] * left[2]
  347. local lxz = -left[1] * left[3]
  348. local lyz = -left[2] * left[3]
  349. rotTemp[1][1] = fxx + uxx + lxx
  350. rotTemp[1][2] = fxy + uxy + lxy
  351. rotTemp[1][3] = fxz + uxz + lxz
  352. rotTemp[2][1] = fxy + uxy + lxy
  353. rotTemp[2][2] = fyy + uyy + lyy
  354. rotTemp[2][3] = fyz + uyz + lyz
  355. rotTemp[3][1] = fxz + uxz + lxz
  356. rotTemp[3][2] = fyz + uyz + lyz
  357. rotTemp[3][3] = fzz + uzz + lzz
  358. MatrixToQuaternion(rotTemp, self)
  359. else
  360. local v = Vector3.Cross(from, to)
  361. local h = (1 - e) / Vector3.Dot(v, v)
  362. local hx = h * v.x
  363. local hz = h * v.z
  364. local hxy = hx * v.y
  365. local hxz = hx * v.z
  366. local hyz = hz * v.y
  367. rotTemp[1][1] = e + hx*v.x
  368. rotTemp[1][2] = hxy - v.z
  369. rotTemp[1][3] = hxz + v.y
  370. rotTemp[2][1] = hxy + v.z
  371. rotTemp[2][2] = e + h*v.y*v.y
  372. rotTemp[2][3] = hyz-v.x
  373. rotTemp[3][1] = hxz - v.y
  374. rotTemp[3][2] = hyz + v.x
  375. rotTemp[3][3] = e + hz*v.z
  376. MatrixToQuaternion(rotTemp, self)
  377. end
  378. end
  379. function Quaternion:Inverse()
  380. local quat = Quaternion.New()
  381. quat.x = -self.x
  382. quat.y = -self.y
  383. quat.z = -self.z
  384. quat.w = self.w
  385. return quat
  386. end
  387. function Quaternion:InverseNonAlloc()
  388. self.x = -self.x
  389. self.y = -self.y
  390. self.z = -self.z
  391. self.w = self.w
  392. end
  393. function Quaternion.Lerp(q1, q2, t)
  394. t = clamp(t, 0, 1)
  395. local q = {x = 0, y = 0, z = 0, w = 1}
  396. if Quaternion.Dot(q1, q2) < 0 then
  397. q.x = q1.x + t * (-q2.x -q1.x)
  398. q.y = q1.y + t * (-q2.y -q1.y)
  399. q.z = q1.z + t * (-q2.z -q1.z)
  400. q.w = q1.w + t * (-q2.w -q1.w)
  401. else
  402. q.x = q1.x + (q2.x - q1.x) * t
  403. q.y = q1.y + (q2.y - q1.y) * t
  404. q.z = q1.z + (q2.z - q1.z) * t
  405. q.w = q1.w + (q2.w - q1.w) * t
  406. end
  407. Quaternion.SetNormalize(q)
  408. setmetatable(q, Quaternion)
  409. return q
  410. end
  411. function Quaternion:LerpNonAlloc(q1, q2, t)
  412. t = clamp(t, 0, 1)
  413. self:Set(0,0,0,1)
  414. local q = self
  415. if Quaternion.Dot(q1, q2) < 0 then
  416. q.x = q1.x + t * (-q2.x -q1.x)
  417. q.y = q1.y + t * (-q2.y -q1.y)
  418. q.z = q1.z + t * (-q2.z -q1.z)
  419. q.w = q1.w + t * (-q2.w -q1.w)
  420. else
  421. q.x = q1.x + (q2.x - q1.x) * t
  422. q.y = q1.y + (q2.y - q1.y) * t
  423. q.z = q1.z + (q2.z - q1.z) * t
  424. q.w = q1.w + (q2.w - q1.w) * t
  425. end
  426. q:SetNormalize()
  427. end
  428. ---@return Quaternion
  429. function Quaternion.LookRotation(forward, up)
  430. local mag = forward.magnitude
  431. if mag < 1e-6 then
  432. error("error input forward to Quaternion.LookRotation"..tostring(forward))
  433. return nil
  434. end
  435. forward = forward / mag
  436. up = up or Vector3.up
  437. local right = Vector3.Cross(up, forward)
  438. right:SetNormalize()
  439. up = Vector3.Cross(forward, right)
  440. right = Vector3.Cross(up, forward)
  441. --[[ local quat = _new(0,0,0,1)
  442. local rot =
  443. {
  444. {right.x, up.x, forward.x},
  445. {right.y, up.y, forward.y},
  446. {right.z, up.z, forward.z},
  447. }
  448. MatrixToQuaternion(rot, quat)
  449. return quat--]]
  450. local t = right.x + up.y + forward.z
  451. if t > 0 then
  452. local x, y, z, w
  453. t = t + 1
  454. local s = 0.5 / sqrt(t)
  455. w = s * t
  456. x = (up.z - forward.y) * s
  457. y = (forward.x - right.z) * s
  458. z = (right.y - up.x) * s
  459. local ret = _new(x, y, z, w)
  460. ret:SetNormalize()
  461. return ret
  462. else
  463. local rot =
  464. {
  465. {right.x, up.x, forward.x},
  466. {right.y, up.y, forward.y},
  467. {right.z, up.z, forward.z},
  468. }
  469. local q = {0, 0, 0}
  470. local i = 1
  471. if up.y > right.x then
  472. i = 2
  473. end
  474. if forward.z > rot[i][i] then
  475. i = 3
  476. end
  477. local j = _next[i]
  478. local k = _next[j]
  479. local t = rot[i][i] - rot[j][j] - rot[k][k] + 1
  480. local s = 0.5 / sqrt(t)
  481. q[i] = s * t
  482. local w = (rot[k][j] - rot[j][k]) * s
  483. q[j] = (rot[j][i] + rot[i][j]) * s
  484. q[k] = (rot[k][i] + rot[i][k]) * s
  485. local ret = _new(q[1], q[2], q[3], w)
  486. ret:SetNormalize()
  487. return ret
  488. end
  489. end
  490. ---@param up Vector3 @内部会修改up的值
  491. function Quaternion:LookRotationNonAlloc(forward, up)
  492. local mag = forward.magnitude
  493. if mag < 1e-6 then
  494. error("error input forward to Quaternion.LookRotation"..tostring(forward))
  495. return nil
  496. end
  497. forward:Set(forward.x/mag,forward.y/mag,forward.z/mag)
  498. if not upTemp then
  499. upTemp = Vector3.zero
  500. end
  501. if not up then
  502. upTemp:Set(0,1,0)
  503. up = upTemp
  504. end
  505. if not rightTemp then
  506. rightTemp = Vector3.zero
  507. end
  508. rightTemp:CrossNonAlloc(up, forward)
  509. local right = rightTemp
  510. right:SetNormalize()
  511. up:CrossNonAlloc(forward, right)
  512. rightTemp:CrossNonAlloc(up, forward)
  513. right = rightTemp
  514. local t = right.x + up.y + forward.z
  515. if t > 0 then
  516. local x, y, z, w
  517. t = t + 1
  518. local s = 0.5 / sqrt(t)
  519. w = s * t
  520. x = (up.z - forward.y) * s
  521. y = (forward.x - right.z) * s
  522. z = (right.y - up.x) * s
  523. self:Set(x,y,z,w)
  524. self:SetNormalize()
  525. else
  526. rotTemp[1][1] = right.x
  527. rotTemp[1][2] = up.x
  528. rotTemp[1][3] = forward.x
  529. rotTemp[2][1] = right.y
  530. rotTemp[2][2] = up.y
  531. rotTemp[2][3] = forward.y
  532. rotTemp[3][1] = right.z
  533. rotTemp[3][2] = up.z
  534. rotTemp[3][3] = forward.z
  535. local q = {0, 0, 0}
  536. local i = 1
  537. if up.y > right.x then
  538. i = 2
  539. end
  540. if forward.z > rotTemp[i][i] then
  541. i = 3
  542. end
  543. local j = _next[i]
  544. local k = _next[j]
  545. local t = rotTemp[i][i] - rotTemp[j][j] - rotTemp[k][k] + 1
  546. local s = 0.5 / sqrt(t)
  547. q[i] = s * t
  548. local w = (rotTemp[k][j] - rotTemp[j][k]) * s
  549. q[j] = (rotTemp[j][i] + rotTemp[i][j]) * s
  550. q[k] = (rotTemp[k][i] + rotTemp[i][k]) * s
  551. self:Set(q[1], q[2], q[3], w)
  552. self:SetNormalize()
  553. end
  554. end
  555. function Quaternion:SetIdentity()
  556. self.x = 0
  557. self.y = 0
  558. self.z = 0
  559. self.w = 1
  560. end
  561. local function UnclampedSlerp(q1, q2, t)
  562. local dot = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w
  563. if dot < 0 then
  564. dot = -dot
  565. q2 = setmetatable({x = -q2.x, y = -q2.y, z = -q2.z, w = -q2.w}, Quaternion)
  566. end
  567. if dot < 0.95 then
  568. local angle = acos(dot)
  569. local invSinAngle = 1 / sin(angle)
  570. local t1 = sin((1 - t) * angle) * invSinAngle
  571. local t2 = sin(t * angle) * invSinAngle
  572. q1 = {x = q1.x * t1 + q2.x * t2, y = q1.y * t1 + q2.y * t2, z = q1.z * t1 + q2.z * t2, w = q1.w * t1 + q2.w * t2}
  573. setmetatable(q1, Quaternion)
  574. return q1
  575. else
  576. q1 = {x = q1.x + t * (q2.x - q1.x), y = q1.y + t * (q2.y - q1.y), z = q1.z + t * (q2.z - q1.z), w = q1.w + t * (q2.w - q1.w)}
  577. Quaternion.SetNormalize(q1)
  578. setmetatable(q1, Quaternion)
  579. return q1
  580. end
  581. end
  582. function Quaternion.Slerp(from, to, t)
  583. if t < 0 then
  584. t = 0
  585. elseif t > 1 then
  586. t = 1
  587. end
  588. return UnclampedSlerp(from, to, t)
  589. end
  590. function Quaternion.RotateTowards(from, to, maxDegreesDelta)
  591. local angle = Quaternion.Angle(from, to)
  592. if angle == 0 then
  593. return to
  594. end
  595. local t = min(1, maxDegreesDelta / angle)
  596. return UnclampedSlerp(from, to, t)
  597. end
  598. local function Approximately(f0, f1)
  599. return abs(f0 - f1) < 1e-6
  600. end
  601. function Quaternion:ToAngleAxis()
  602. local angle = 2 * acos(self.w)
  603. if Approximately(angle, 0) then
  604. return angle * 57.29578, Vector3.New(1, 0, 0)
  605. end
  606. local div = 1 / sqrt(1 - sqrt(self.w))
  607. return angle * 57.29578, Vector3.New(self.x * div, self.y * div, self.z * div)
  608. end
  609. local pi = Mathf.PI
  610. local half_pi = pi * 0.5
  611. local two_pi = 2 * pi
  612. local negativeFlip = -0.0001
  613. local positiveFlip = two_pi - 0.0001
  614. local function SanitizeEuler(euler)
  615. if euler.x < negativeFlip then
  616. euler.x = euler.x + two_pi
  617. elseif euler.x > positiveFlip then
  618. euler.x = euler.x - two_pi
  619. end
  620. if euler.y < negativeFlip then
  621. euler.y = euler.y + two_pi
  622. elseif euler.y > positiveFlip then
  623. euler.y = euler.y - two_pi
  624. end
  625. if euler.z < negativeFlip then
  626. euler.z = euler.z + two_pi
  627. elseif euler.z > positiveFlip then
  628. euler.z = euler.z + two_pi
  629. end
  630. end
  631. --from http://www.geometrictools.com/Documentation/EulerAngles.pdf
  632. --Order of rotations: YXZ
  633. function Quaternion:ToEulerAngles()
  634. local x = self.x
  635. local y = self.y
  636. local z = self.z
  637. local w = self.w
  638. local check = 2 * (y * z - w * x)
  639. if check < 0.999 then
  640. if check > -0.999 then
  641. local v = Vector3.New( -asin(check),
  642. atan2(2 * (x * z + w * y), 1 - 2 * (x * x + y * y)),
  643. atan2(2 * (x * y + w * z), 1 - 2 * (x * x + z * z)))
  644. SanitizeEuler(v)
  645. v:Mul(rad2Deg)
  646. return v
  647. else
  648. local v = Vector3.New(half_pi, atan2(2 * (x * y - w * z), 1 - 2 * (y * y + z * z)), 0)
  649. SanitizeEuler(v)
  650. v:Mul(rad2Deg)
  651. return v
  652. end
  653. else
  654. local v = Vector3.New(-half_pi, atan2(-2 * (x * y - w * z), 1 - 2 * (y * y + z * z)), 0)
  655. SanitizeEuler(v)
  656. v:Mul(rad2Deg)
  657. return v
  658. end
  659. end
  660. ---@param v Vector3
  661. function Quaternion:ToEulerAnglesNoAlloc(v)
  662. local x = self.x
  663. local y = self.y
  664. local z = self.z
  665. local w = self.w
  666. local check = 2 * (y * z - w * x)
  667. if check < 0.999 then
  668. if check > -0.999 then
  669. v:Set( -asin(check),
  670. atan2(2 * (x * z + w * y), 1 - 2 * (x * x + y * y)),
  671. atan2(2 * (x * y + w * z), 1 - 2 * (x * x + z * z)))
  672. SanitizeEuler(v)
  673. v:Mul(rad2Deg)
  674. return v
  675. else
  676. v:Set(half_pi, atan2(2 * (x * y - w * z), 1 - 2 * (y * y + z * z)), 0)
  677. SanitizeEuler(v)
  678. v:Mul(rad2Deg)
  679. return v
  680. end
  681. else
  682. v:Set(-half_pi, atan2(-2 * (x * y - w * z), 1 - 2 * (y * y + z * z)), 0)
  683. SanitizeEuler(v)
  684. v:Mul(rad2Deg)
  685. return v
  686. end
  687. end
  688. function Quaternion:Forward()
  689. return self:MulVec3(Vector3.forward)
  690. end
  691. function Quaternion.MulVec3(self, point)
  692. local vec = Vector3.New()
  693. local num = self.x * 2
  694. local num2 = self.y * 2
  695. local num3 = self.z * 2
  696. local num4 = self.x * num
  697. local num5 = self.y * num2
  698. local num6 = self.z * num3
  699. local num7 = self.x * num2
  700. local num8 = self.x * num3
  701. local num9 = self.y * num3
  702. local num10 = self.w * num
  703. local num11 = self.w * num2
  704. local num12 = self.w * num3
  705. vec.x = (((1 - (num5 + num6)) * point.x) + ((num7 - num12) * point.y)) + ((num8 + num11) * point.z)
  706. vec.y = (((num7 + num12) * point.x) + ((1 - (num4 + num6)) * point.y)) + ((num9 - num10) * point.z)
  707. vec.z = (((num8 - num11) * point.x) + ((num9 + num10) * point.y)) + ((1 - (num4 + num5)) * point.z)
  708. return vec
  709. end
  710. function Quaternion.MulQuaternion(lhs, rhs)
  711. return Quaternion.New((((lhs.w * rhs.x) + (lhs.x * rhs.w)) + (lhs.y * rhs.z)) - (lhs.z * rhs.y), (((lhs.w * rhs.y) + (lhs.y * rhs.w)) + (lhs.z * rhs.x)) - (lhs.x * rhs.z), (((lhs.w * rhs.z) + (lhs.z * rhs.w)) + (lhs.x * rhs.y)) - (lhs.y * rhs.x), (((lhs.w * rhs.w) - (lhs.x * rhs.x)) - (lhs.y * rhs.y)) - (lhs.z * rhs.z))
  712. end
  713. Quaternion.__mul = function(lhs, rhs)
  714. if Vector3 == getmetatable(rhs) then
  715. return lhs:MulVec3(rhs)
  716. elseif Quaternion == getmetatable(rhs) then
  717. return Quaternion.New((((lhs.w * rhs.x) + (lhs.x * rhs.w)) + (lhs.y * rhs.z)) - (lhs.z * rhs.y), (((lhs.w * rhs.y) + (lhs.y * rhs.w)) + (lhs.z * rhs.x)) - (lhs.x * rhs.z), (((lhs.w * rhs.z) + (lhs.z * rhs.w)) + (lhs.x * rhs.y)) - (lhs.y * rhs.x), (((lhs.w * rhs.w) - (lhs.x * rhs.x)) - (lhs.y * rhs.y)) - (lhs.z * rhs.z))
  718. end
  719. end
  720. Quaternion.__unm = function(q)
  721. return Quaternion.New(-q.x, -q.y, -q.z, -q.w)
  722. end
  723. Quaternion.__eq = function(lhs,rhs)
  724. if not lhs.x or not rhs.x then
  725. return false
  726. end
  727. return Quaternion.Dot(lhs, rhs) > 0.999999
  728. end
  729. Quaternion.__tostring = function(self)
  730. return "["..self.x..","..self.y..","..self.z..","..self.w.."]"
  731. end
  732. _getter.identity = function() return _new(0, 0, 0, 1) end
  733. _getter.eulerAngles = Quaternion.ToEulerAngles
  734. Quaternion.unity_quaternion = CS.UnityEngine.Quaternion
  735. CS.UnityEngine.Quaternion = Quaternion
  736. ---@param vec Vector4
  737. function Quaternion:IsSelfMetatable(vec)
  738. return self.x == nil
  739. end
  740. setmetatable(Quaternion, Quaternion)