Quaternion.lua 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  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. local math = math
  7. local sin = math.sin
  8. local cos = math.cos
  9. local acos = math.acos
  10. local asin = math.asin
  11. local sqrt = math.sqrt
  12. local min = math.min
  13. local max = math.max
  14. local sign = math.sign
  15. local atan2 = math.atan2
  16. local clamp = Mathf.Clamp
  17. local abs = math.abs
  18. local setmetatable = setmetatable
  19. local getmetatable = getmetatable
  20. local rawget = rawget
  21. local rawset = rawset
  22. local Vector3 = Vector3
  23. local rad2Deg = Mathf.Rad2Deg
  24. local halfDegToRad = 0.5 * Mathf.Deg2Rad
  25. local _forward = Vector3.forward
  26. local _up = Vector3.up
  27. local _next = { 2, 3, 1 }
  28. local Quaternion = {}
  29. local get = tolua.initget(Quaternion)
  30. Quaternion.__index = function(t, k)
  31. local var = rawget(Quaternion, k)
  32. if var == nil then
  33. var = rawget(get, k)
  34. if var ~= nil then
  35. return var(t)
  36. end
  37. end
  38. return var
  39. end
  40. Quaternion.__newindex = function(t, name, k)
  41. if name == "eulerAngles" then
  42. t:SetEuler(k)
  43. else
  44. rawset(t, name, k)
  45. end
  46. end
  47. function Quaternion.New(x, y, z, w)
  48. local t = {x = x or 0, y = y or 0, z = z or 0, w = w or 0}
  49. setmetatable(t, Quaternion)
  50. return t
  51. end
  52. local _new = Quaternion.New
  53. Quaternion.__call = function(t, x, y, z, w)
  54. local t = {x = x or 0, y = y or 0, z = z or 0, w = w or 0}
  55. setmetatable(t, Quaternion)
  56. return t
  57. end
  58. function Quaternion:Set(x,y,z,w)
  59. self.x = x or 0
  60. self.y = y or 0
  61. self.z = z or 0
  62. self.w = w or 0
  63. end
  64. function Quaternion:Clone()
  65. return _new(self.x, self.y, self.z, self.w)
  66. end
  67. function Quaternion:Get()
  68. return self.x, self.y, self.z, self.w
  69. end
  70. function Quaternion.Dot(a, b)
  71. return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w
  72. end
  73. function Quaternion.Angle(a, b)
  74. local dot = Quaternion.Dot(a, b)
  75. if dot < 0 then dot = -dot end
  76. return acos(min(dot, 1)) * 2 * 57.29578
  77. end
  78. function Quaternion.AngleAxis(angle, axis)
  79. local normAxis = axis:Normalize()
  80. angle = angle * halfDegToRad
  81. local s = sin(angle)
  82. local w = cos(angle)
  83. local x = normAxis.x * s
  84. local y = normAxis.y * s
  85. local z = normAxis.z * s
  86. return _new(x,y,z,w)
  87. end
  88. function Quaternion.Equals(a, b)
  89. return a.x == b.x and a.y == b.y and a.z == b.z and a.w == b.w
  90. end
  91. function Quaternion.Euler(x, y, z)
  92. if y == nil and z == nil then
  93. y = x.y
  94. z = x.z
  95. x = x.x
  96. end
  97. x = x * 0.0087266462599716
  98. y = y * 0.0087266462599716
  99. z = z * 0.0087266462599716
  100. local sinX = sin(x)
  101. x = cos(x)
  102. local sinY = sin(y)
  103. y = cos(y)
  104. local sinZ = sin(z)
  105. z = cos(z)
  106. 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}
  107. setmetatable(q, Quaternion)
  108. return q
  109. end
  110. function Quaternion:SetEuler(x, y, z)
  111. if y == nil and z == nil then
  112. y = x.y
  113. z = x.z
  114. x = x.x
  115. end
  116. x = x * 0.0087266462599716
  117. y = y * 0.0087266462599716
  118. z = z * 0.0087266462599716
  119. local sinX = sin(x)
  120. local cosX = cos(x)
  121. local sinY = sin(y)
  122. local cosY = cos(y)
  123. local sinZ = sin(z)
  124. local cosZ = cos(z)
  125. self.w = cosY * cosX * cosZ + sinY * sinX * sinZ
  126. self.x = cosY * sinX * cosZ + sinY * cosX * sinZ
  127. self.y = sinY * cosX * cosZ - cosY * sinX * sinZ
  128. self.z = cosY * cosX * sinZ - sinY * sinX * cosZ
  129. return self
  130. end
  131. function Quaternion:Normalize()
  132. local quat = self:Clone()
  133. quat:SetNormalize()
  134. return quat
  135. end
  136. function Quaternion:SetNormalize()
  137. local n = self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w
  138. if n ~= 1 and n > 0 then
  139. n = 1 / sqrt(n)
  140. self.x = self.x * n
  141. self.y = self.y * n
  142. self.z = self.z * n
  143. self.w = self.w * n
  144. end
  145. end
  146. --产生一个新的从from到to的四元数
  147. function Quaternion.FromToRotation(from, to)
  148. local quat = Quaternion.New()
  149. quat:SetFromToRotation(from, to)
  150. return quat
  151. end
  152. --设置当前四元数为 from 到 to的旋转, 注意from和to同 forward平行会同unity不一致
  153. function Quaternion:SetFromToRotation1(from, to)
  154. local v0 = from:Normalize()
  155. local v1 = to:Normalize()
  156. local d = Vector3.Dot(v0, v1)
  157. if d > -1 + 1e-6 then
  158. local s = sqrt((1+d) * 2)
  159. local invs = 1 / s
  160. local c = Vector3.Cross(v0, v1) * invs
  161. self:Set(c.x, c.y, c.z, s * 0.5)
  162. elseif d > 1 - 1e-6 then
  163. return _new(0, 0, 0, 1)
  164. else
  165. local axis = Vector3.Cross(Vector3.right, v0)
  166. if axis:SqrMagnitude() < 1e-6 then
  167. axis = Vector3.Cross(Vector3.forward, v0)
  168. end
  169. self:Set(axis.x, axis.y, axis.z, 0)
  170. return self
  171. end
  172. return self
  173. end
  174. local function MatrixToQuaternion(rot, quat)
  175. local trace = rot[1][1] + rot[2][2] + rot[3][3]
  176. if trace > 0 then
  177. local s = sqrt(trace + 1)
  178. quat.w = 0.5 * s
  179. s = 0.5 / s
  180. quat.x = (rot[3][2] - rot[2][3]) * s
  181. quat.y = (rot[1][3] - rot[3][1]) * s
  182. quat.z = (rot[2][1] - rot[1][2]) * s
  183. quat:SetNormalize()
  184. else
  185. local i = 1
  186. local q = {0, 0, 0}
  187. if rot[2][2] > rot[1][1] then
  188. i = 2
  189. end
  190. if rot[3][3] > rot[i][i] then
  191. i = 3
  192. end
  193. local j = _next[i]
  194. local k = _next[j]
  195. local t = rot[i][i] - rot[j][j] - rot[k][k] + 1
  196. local s = 0.5 / sqrt(t)
  197. q[i] = s * t
  198. local w = (rot[k][j] - rot[j][k]) * s
  199. q[j] = (rot[j][i] + rot[i][j]) * s
  200. q[k] = (rot[k][i] + rot[i][k]) * s
  201. quat:Set(q[1], q[2], q[3], w)
  202. quat:SetNormalize()
  203. end
  204. end
  205. function Quaternion:SetFromToRotation(from, to)
  206. from = from:Normalize()
  207. to = to:Normalize()
  208. local e = Vector3.Dot(from, to)
  209. if e > 1 - 1e-6 then
  210. self:Set(0, 0, 0, 1)
  211. elseif e < -1 + 1e-6 then
  212. local left = {0, from.z, from.y}
  213. local mag = left[2] * left[2] + left[3] * left[3] --+ left[1] * left[1] = 0
  214. if mag < 1e-6 then
  215. left[1] = -from.z
  216. left[2] = 0
  217. left[3] = from.x
  218. mag = left[1] * left[1] + left[3] * left[3]
  219. end
  220. local invlen = 1/sqrt(mag)
  221. left[1] = left[1] * invlen
  222. left[2] = left[2] * invlen
  223. left[3] = left[3] * invlen
  224. local up = {0, 0, 0}
  225. up[1] = left[2] * from.z - left[3] * from.y
  226. up[2] = left[3] * from.x - left[1] * from.z
  227. up[3] = left[1] * from.y - left[2] * from.x
  228. local fxx = -from.x * from.x
  229. local fyy = -from.y * from.y
  230. local fzz = -from.z * from.z
  231. local fxy = -from.x * from.y
  232. local fxz = -from.x * from.z
  233. local fyz = -from.y * from.z
  234. local uxx = up[1] * up[1]
  235. local uyy = up[2] * up[2]
  236. local uzz = up[3] * up[3]
  237. local uxy = up[1] * up[2]
  238. local uxz = up[1] * up[3]
  239. local uyz = up[2] * up[3]
  240. local lxx = -left[1] * left[1]
  241. local lyy = -left[2] * left[2]
  242. local lzz = -left[3] * left[3]
  243. local lxy = -left[1] * left[2]
  244. local lxz = -left[1] * left[3]
  245. local lyz = -left[2] * left[3]
  246. local rot =
  247. {
  248. {fxx + uxx + lxx, fxy + uxy + lxy, fxz + uxz + lxz},
  249. {fxy + uxy + lxy, fyy + uyy + lyy, fyz + uyz + lyz},
  250. {fxz + uxz + lxz, fyz + uyz + lyz, fzz + uzz + lzz},
  251. }
  252. MatrixToQuaternion(rot, self)
  253. else
  254. local v = Vector3.Cross(from, to)
  255. local h = (1 - e) / Vector3.Dot(v, v)
  256. local hx = h * v.x
  257. local hz = h * v.z
  258. local hxy = hx * v.y
  259. local hxz = hx * v.z
  260. local hyz = hz * v.y
  261. local rot =
  262. {
  263. {e + hx*v.x, hxy - v.z, hxz + v.y},
  264. {hxy + v.z, e + h*v.y*v.y, hyz-v.x},
  265. {hxz - v.y, hyz + v.x, e + hz*v.z},
  266. }
  267. MatrixToQuaternion(rot, self)
  268. end
  269. end
  270. function Quaternion:Inverse()
  271. local quat = Quaternion.New()
  272. quat.x = -self.x
  273. quat.y = -self.y
  274. quat.z = -self.z
  275. quat.w = self.w
  276. return quat
  277. end
  278. function Quaternion.Lerp(q1, q2, t)
  279. t = clamp(t, 0, 1)
  280. local q = {x = 0, y = 0, z = 0, w = 1}
  281. if Quaternion.Dot(q1, q2) < 0 then
  282. q.x = q1.x + t * (-q2.x -q1.x)
  283. q.y = q1.y + t * (-q2.y -q1.y)
  284. q.z = q1.z + t * (-q2.z -q1.z)
  285. q.w = q1.w + t * (-q2.w -q1.w)
  286. else
  287. q.x = q1.x + (q2.x - q1.x) * t
  288. q.y = q1.y + (q2.y - q1.y) * t
  289. q.z = q1.z + (q2.z - q1.z) * t
  290. q.w = q1.w + (q2.w - q1.w) * t
  291. end
  292. Quaternion.SetNormalize(q)
  293. setmetatable(q, Quaternion)
  294. return q
  295. end
  296. function Quaternion.LookRotation(forward, up)
  297. local mag = forward:Magnitude()
  298. if mag < 1e-6 then
  299. error("error input forward to Quaternion.LookRotation"..tostring(forward))
  300. return nil
  301. end
  302. forward = forward / mag
  303. up = up or _up
  304. local right = Vector3.Cross(up, forward)
  305. right:SetNormalize()
  306. up = Vector3.Cross(forward, right)
  307. right = Vector3.Cross(up, forward)
  308. --[[ local quat = _new(0,0,0,1)
  309. local rot =
  310. {
  311. {right.x, up.x, forward.x},
  312. {right.y, up.y, forward.y},
  313. {right.z, up.z, forward.z},
  314. }
  315. MatrixToQuaternion(rot, quat)
  316. return quat--]]
  317. local t = right.x + up.y + forward.z
  318. if t > 0 then
  319. local x, y, z, w
  320. t = t + 1
  321. local s = 0.5 / sqrt(t)
  322. w = s * t
  323. x = (up.z - forward.y) * s
  324. y = (forward.x - right.z) * s
  325. z = (right.y - up.x) * s
  326. local ret = _new(x, y, z, w)
  327. ret:SetNormalize()
  328. return ret
  329. else
  330. local rot =
  331. {
  332. {right.x, up.x, forward.x},
  333. {right.y, up.y, forward.y},
  334. {right.z, up.z, forward.z},
  335. }
  336. local q = {0, 0, 0}
  337. local i = 1
  338. if up.y > right.x then
  339. i = 2
  340. end
  341. if forward.z > rot[i][i] then
  342. i = 3
  343. end
  344. local j = _next[i]
  345. local k = _next[j]
  346. local t = rot[i][i] - rot[j][j] - rot[k][k] + 1
  347. local s = 0.5 / sqrt(t)
  348. q[i] = s * t
  349. local w = (rot[k][j] - rot[j][k]) * s
  350. q[j] = (rot[j][i] + rot[i][j]) * s
  351. q[k] = (rot[k][i] + rot[i][k]) * s
  352. local ret = _new(q[1], q[2], q[3], w)
  353. ret:SetNormalize()
  354. return ret
  355. end
  356. end
  357. function Quaternion:SetIdentity()
  358. self.x = 0
  359. self.y = 0
  360. self.z = 0
  361. self.w = 1
  362. end
  363. local function UnclampedSlerp(q1, q2, t)
  364. local dot = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w
  365. if dot < 0 then
  366. dot = -dot
  367. q2 = setmetatable({x = -q2.x, y = -q2.y, z = -q2.z, w = -q2.w}, Quaternion)
  368. end
  369. if dot < 0.95 then
  370. local angle = acos(dot)
  371. local invSinAngle = 1 / sin(angle)
  372. local t1 = sin((1 - t) * angle) * invSinAngle
  373. local t2 = sin(t * angle) * invSinAngle
  374. 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}
  375. setmetatable(q1, Quaternion)
  376. return q1
  377. else
  378. 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)}
  379. Quaternion.SetNormalize(q1)
  380. setmetatable(q1, Quaternion)
  381. return q1
  382. end
  383. end
  384. function Quaternion.Slerp(from, to, t)
  385. if t < 0 then
  386. t = 0
  387. elseif t > 1 then
  388. t = 1
  389. end
  390. return UnclampedSlerp(from, to, t)
  391. end
  392. function Quaternion.RotateTowards(from, to, maxDegreesDelta)
  393. local angle = Quaternion.Angle(from, to)
  394. if angle == 0 then
  395. return to
  396. end
  397. local t = min(1, maxDegreesDelta / angle)
  398. return UnclampedSlerp(from, to, t)
  399. end
  400. local function Approximately(f0, f1)
  401. return abs(f0 - f1) < 1e-6
  402. end
  403. function Quaternion:ToAngleAxis()
  404. local angle = 2 * acos(self.w)
  405. if Approximately(angle, 0) then
  406. return angle * 57.29578, Vector3.New(1, 0, 0)
  407. end
  408. local div = 1 / sqrt(1 - sqrt(self.w))
  409. return angle * 57.29578, Vector3.New(self.x * div, self.y * div, self.z * div)
  410. end
  411. local pi = Mathf.PI
  412. local half_pi = pi * 0.5
  413. local two_pi = 2 * pi
  414. local negativeFlip = -0.0001
  415. local positiveFlip = two_pi - 0.0001
  416. local function SanitizeEuler(euler)
  417. if euler.x < negativeFlip then
  418. euler.x = euler.x + two_pi
  419. elseif euler.x > positiveFlip then
  420. euler.x = euler.x - two_pi
  421. end
  422. if euler.y < negativeFlip then
  423. euler.y = euler.y + two_pi
  424. elseif euler.y > positiveFlip then
  425. euler.y = euler.y - two_pi
  426. end
  427. if euler.z < negativeFlip then
  428. euler.z = euler.z + two_pi
  429. elseif euler.z > positiveFlip then
  430. euler.z = euler.z + two_pi
  431. end
  432. end
  433. --from http://www.geometrictools.com/Documentation/EulerAngles.pdf
  434. --Order of rotations: YXZ
  435. function Quaternion:ToEulerAngles()
  436. local x = self.x
  437. local y = self.y
  438. local z = self.z
  439. local w = self.w
  440. local check = 2 * (y * z - w * x)
  441. if check < 0.999 then
  442. if check > -0.999 then
  443. local v = Vector3.New( -asin(check),
  444. atan2(2 * (x * z + w * y), 1 - 2 * (x * x + y * y)),
  445. atan2(2 * (x * y + w * z), 1 - 2 * (x * x + z * z)))
  446. SanitizeEuler(v)
  447. v:Mul(rad2Deg)
  448. return v
  449. else
  450. local v = Vector3.New(half_pi, atan2(2 * (x * y - w * z), 1 - 2 * (y * y + z * z)), 0)
  451. SanitizeEuler(v)
  452. v:Mul(rad2Deg)
  453. return v
  454. end
  455. else
  456. local v = Vector3.New(-half_pi, atan2(-2 * (x * y - w * z), 1 - 2 * (y * y + z * z)), 0)
  457. SanitizeEuler(v)
  458. v:Mul(rad2Deg)
  459. return v
  460. end
  461. end
  462. function Quaternion:Forward()
  463. return self:MulVec3(_forward)
  464. end
  465. function Quaternion.MulVec3(self, point)
  466. local vec = Vector3.New()
  467. local num = self.x * 2
  468. local num2 = self.y * 2
  469. local num3 = self.z * 2
  470. local num4 = self.x * num
  471. local num5 = self.y * num2
  472. local num6 = self.z * num3
  473. local num7 = self.x * num2
  474. local num8 = self.x * num3
  475. local num9 = self.y * num3
  476. local num10 = self.w * num
  477. local num11 = self.w * num2
  478. local num12 = self.w * num3
  479. vec.x = (((1 - (num5 + num6)) * point.x) + ((num7 - num12) * point.y)) + ((num8 + num11) * point.z)
  480. vec.y = (((num7 + num12) * point.x) + ((1 - (num4 + num6)) * point.y)) + ((num9 - num10) * point.z)
  481. vec.z = (((num8 - num11) * point.x) + ((num9 + num10) * point.y)) + ((1 - (num4 + num5)) * point.z)
  482. return vec
  483. end
  484. Quaternion.__mul = function(lhs, rhs)
  485. if Quaternion == getmetatable(rhs) then
  486. 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))
  487. elseif Vector3 == getmetatable(rhs) then
  488. return lhs:MulVec3(rhs)
  489. end
  490. end
  491. Quaternion.__unm = function(q)
  492. return Quaternion.New(-q.x, -q.y, -q.z, -q.w)
  493. end
  494. Quaternion.__eq = function(lhs,rhs)
  495. return Quaternion.Dot(lhs, rhs) > 0.999999
  496. end
  497. Quaternion.__tostring = function(self)
  498. return "["..self.x..","..self.y..","..self.z..","..self.w.."]"
  499. end
  500. get.identity = function() return _new(0, 0, 0, 1) end
  501. get.eulerAngles = Quaternion.ToEulerAngles
  502. UnityEngine.Quaternion = Quaternion
  503. setmetatable(Quaternion, Quaternion)
  504. return Quaternion