ODESitAvatar.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. // Ubit Umarov 2012
  28. using System;
  29. using System.Collections.Generic;
  30. using OpenSim.Region.PhysicsModules.SharedBase;
  31. using OpenMetaverse;
  32. namespace OpenSim.Region.PhysicsModule.ubOde
  33. {
  34. /// <summary>
  35. /// </summary>
  36. public class ODESitAvatar
  37. {
  38. private ODEScene m_scene;
  39. private ODERayCastRequestManager m_raymanager;
  40. public ODESitAvatar(ODEScene pScene, ODERayCastRequestManager raymanager)
  41. {
  42. m_scene = pScene;
  43. m_raymanager = raymanager;
  44. }
  45. private static Vector3 SitAjust = new Vector3(0, 0, 0.4f);
  46. private const RayFilterFlags RaySitFlags = RayFilterFlags.AllPrims | RayFilterFlags.ClosestHit;
  47. private void RotAroundZ(float x, float y, ref Quaternion ori)
  48. {
  49. double ang = Math.Atan2(y, x);
  50. ang *= 0.5d;
  51. float s = (float)Math.Sin(ang);
  52. float c = (float)Math.Cos(ang);
  53. ori.X = 0;
  54. ori.Y = 0;
  55. ori.Z = s;
  56. ori.W = c;
  57. }
  58. public void Sit(PhysicsActor actor, Vector3 avPos, Vector3 avCameraPosition, Vector3 offset, Vector3 avOffset, SitAvatarCallback PhysicsSitResponse)
  59. {
  60. if (!m_scene.haveActor(actor) || !(actor is OdePrim) || ((OdePrim)actor).prim_geom == IntPtr.Zero)
  61. {
  62. PhysicsSitResponse(-1, actor.LocalID, offset, Quaternion.Identity);
  63. return;
  64. }
  65. IntPtr geom = ((OdePrim)actor).prim_geom;
  66. Vector3 geopos = SafeNativeMethods.GeomGetPositionOMV(geom);
  67. Quaternion geomOri = SafeNativeMethods.GeomGetQuaternionOMV(geom);
  68. // Vector3 geopos = actor.Position;
  69. // Quaternion geomOri = actor.Orientation;
  70. Quaternion geomInvOri = Quaternion.Conjugate(geomOri);
  71. Quaternion ori = Quaternion.Identity;
  72. Vector3 rayDir = geopos + offset - avCameraPosition;
  73. float raylen = rayDir.Length();
  74. if (raylen < 0.001f)
  75. {
  76. PhysicsSitResponse(-1, actor.LocalID, offset, Quaternion.Identity);
  77. return;
  78. }
  79. float t = 1 / raylen;
  80. rayDir.X *= t;
  81. rayDir.Y *= t;
  82. rayDir.Z *= t;
  83. raylen += 30f; // focal point may be far
  84. List<ContactResult> rayResults;
  85. rayResults = m_scene.RaycastActor(actor, avCameraPosition, rayDir, raylen, 1, RaySitFlags);
  86. if (rayResults.Count == 0)
  87. {
  88. /* if this fundamental ray failed, then just fail so user can try another spot and not be sitted far on a big prim
  89. d.AABB aabb;
  90. d.GeomGetAABB(geom, out aabb);
  91. offset = new Vector3(avOffset.X, 0, aabb.MaxZ + avOffset.Z - geopos.Z);
  92. ori = geomInvOri;
  93. offset *= geomInvOri;
  94. PhysicsSitResponse(1, actor.LocalID, offset, ori);
  95. */
  96. PhysicsSitResponse(0, actor.LocalID, offset, ori);
  97. return;
  98. }
  99. int status = 1;
  100. offset = rayResults[0].Pos - geopos;
  101. SafeNativeMethods.GeomClassID geoclass = SafeNativeMethods.GeomGetClass(geom);
  102. if (geoclass == SafeNativeMethods.GeomClassID.SphereClass)
  103. {
  104. float r = SafeNativeMethods.GeomSphereGetRadius(geom);
  105. offset.Normalize();
  106. offset *= r;
  107. RotAroundZ(offset.X, offset.Y, ref ori);
  108. if (r < 0.4f)
  109. {
  110. offset = new Vector3(0, 0, r);
  111. }
  112. else
  113. {
  114. if (offset.Z < 0.4f)
  115. {
  116. t = offset.Z;
  117. float rsq = r * r;
  118. t = 1.0f / (rsq - t * t);
  119. offset.X *= t;
  120. offset.Y *= t;
  121. offset.Z = 0.4f;
  122. t = rsq - 0.16f;
  123. offset.X *= t;
  124. offset.Y *= t;
  125. }
  126. else if (r > 0.8f && offset.Z > 0.8f * r)
  127. {
  128. status = 3;
  129. avOffset.X = -avOffset.X;
  130. avOffset.Z *= 1.6f;
  131. }
  132. }
  133. offset += avOffset * ori;
  134. ori = geomInvOri * ori;
  135. offset *= geomInvOri;
  136. PhysicsSitResponse(status, actor.LocalID, offset, ori);
  137. return;
  138. }
  139. Vector3 norm = rayResults[0].Normal;
  140. if (norm.Z < -0.4f)
  141. {
  142. PhysicsSitResponse(0, actor.LocalID, offset, Quaternion.Identity);
  143. return;
  144. }
  145. float SitNormX = -rayDir.X;
  146. float SitNormY = -rayDir.Y;
  147. Vector3 pivot = geopos + offset;
  148. float edgeNormalX = norm.X;
  149. float edgeNormalY = norm.Y;
  150. float edgeDirX = -rayDir.X;
  151. float edgeDirY = -rayDir.Y;
  152. Vector3 edgePos = rayResults[0].Pos;
  153. float edgeDist = float.MaxValue;
  154. bool foundEdge = false;
  155. if (norm.Z < 0.5f)
  156. {
  157. float rayDist = 4.0f;
  158. for (int i = 0; i < 6; i++)
  159. {
  160. pivot.X -= 0.01f * norm.X;
  161. pivot.Y -= 0.01f * norm.Y;
  162. pivot.Z -= 0.01f * norm.Z;
  163. rayDir.X = -norm.X * norm.Z;
  164. rayDir.Y = -norm.Y * norm.Z;
  165. rayDir.Z = 1.0f - norm.Z * norm.Z;
  166. rayDir.Normalize();
  167. rayResults = m_scene.RaycastActor(actor, pivot, rayDir, rayDist, 1, RayFilterFlags.AllPrims);
  168. if (rayResults.Count == 0)
  169. break;
  170. if (Math.Abs(rayResults[0].Normal.Z) < 0.7f)
  171. {
  172. rayDist -= rayResults[0].Depth;
  173. if (rayDist < 0f)
  174. break;
  175. pivot = rayResults[0].Pos;
  176. norm = rayResults[0].Normal;
  177. edgeNormalX = norm.X;
  178. edgeNormalY = norm.Y;
  179. edgeDirX = -rayDir.X;
  180. edgeDirY = -rayDir.Y;
  181. }
  182. else
  183. {
  184. foundEdge = true;
  185. edgePos = rayResults[0].Pos;
  186. break;
  187. }
  188. }
  189. if (!foundEdge)
  190. {
  191. PhysicsSitResponse(0, actor.LocalID, offset, ori);
  192. return;
  193. }
  194. avOffset.X *= 0.5f;
  195. }
  196. else if (norm.Z > 0.866f)
  197. {
  198. float toCamBaseX = avCameraPosition.X - pivot.X;
  199. float toCamBaseY = avCameraPosition.Y - pivot.Y;
  200. float toCamX = toCamBaseX;
  201. float toCamY = toCamBaseY;
  202. for (int j = 0; j < 4; j++)
  203. {
  204. float rayDist = 1.0f;
  205. float curEdgeDist = 0.0f;
  206. for (int i = 0; i < 3; i++)
  207. {
  208. pivot.Z -= 0.01f;
  209. rayDir.X = toCamX;
  210. rayDir.Y = toCamY;
  211. rayDir.Z = (-toCamX * norm.X - toCamY * norm.Y) / norm.Z;
  212. rayDir.Normalize();
  213. rayResults = m_scene.RaycastActor(actor, pivot, rayDir, rayDist, 1, RayFilterFlags.AllPrims);
  214. if (rayResults.Count == 0)
  215. break;
  216. curEdgeDist += rayResults[0].Depth;
  217. if (rayResults[0].Normal.Z > 0.5f)
  218. {
  219. rayDist -= rayResults[0].Depth;
  220. if (rayDist < 0f)
  221. break;
  222. pivot = rayResults[0].Pos;
  223. norm = rayResults[0].Normal;
  224. }
  225. else
  226. {
  227. foundEdge = true;
  228. if (curEdgeDist < edgeDist)
  229. {
  230. edgeDist = curEdgeDist;
  231. edgeNormalX = rayResults[0].Normal.X;
  232. edgeNormalY = rayResults[0].Normal.Y;
  233. edgeDirX = rayDir.X;
  234. edgeDirY = rayDir.Y;
  235. edgePos = rayResults[0].Pos;
  236. }
  237. break;
  238. }
  239. }
  240. if (foundEdge && edgeDist < 0.2f)
  241. break;
  242. pivot = geopos + offset;
  243. switch (j)
  244. {
  245. case 0:
  246. toCamX = -toCamBaseY;
  247. toCamY = toCamBaseX;
  248. break;
  249. case 1:
  250. toCamX = toCamBaseY;
  251. toCamY = -toCamBaseX;
  252. break;
  253. case 2:
  254. toCamX = -toCamBaseX;
  255. toCamY = -toCamBaseY;
  256. break;
  257. default:
  258. break;
  259. }
  260. }
  261. if (!foundEdge)
  262. {
  263. avOffset.X = -avOffset.X;
  264. avOffset.Z *= 1.6f;
  265. RotAroundZ(SitNormX, SitNormY, ref ori);
  266. offset += avOffset * ori;
  267. ori = geomInvOri * ori;
  268. offset *= geomInvOri;
  269. PhysicsSitResponse(3, actor.LocalID, offset, ori);
  270. return;
  271. }
  272. avOffset.X *= 0.5f;
  273. }
  274. SitNormX = edgeNormalX;
  275. SitNormY = edgeNormalY;
  276. if (edgeDirX * SitNormX + edgeDirY * SitNormY < 0)
  277. {
  278. SitNormX = -SitNormX;
  279. SitNormY = -SitNormY;
  280. }
  281. RotAroundZ(SitNormX, SitNormY, ref ori);
  282. offset = edgePos + avOffset * ori;
  283. offset -= geopos;
  284. ori = geomInvOri * ori;
  285. offset *= geomInvOri;
  286. PhysicsSitResponse(1, actor.LocalID, offset, ori);
  287. return;
  288. }
  289. }
  290. }