diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Physics/UbitOdePlugin/ODESitAvatar.cs | 288 |
1 files changed, 230 insertions, 58 deletions
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODESitAvatar.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODESitAvatar.cs index 225bff8..ecc732a 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODESitAvatar.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODESitAvatar.cs | |||
@@ -52,6 +52,21 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
52 | } | 52 | } |
53 | 53 | ||
54 | private static Vector3 SitAjust = new Vector3(0, 0, 0.4f); | 54 | private static Vector3 SitAjust = new Vector3(0, 0, 0.4f); |
55 | private const RayFilterFlags RaySitFlags = RayFilterFlags.AllPrims | RayFilterFlags.ClosestHit; | ||
56 | |||
57 | private void RotAroundZ(float x, float y, ref Quaternion ori) | ||
58 | { | ||
59 | double ang = Math.Atan2(y, x); | ||
60 | ang *= 0.5d; | ||
61 | float s = (float)Math.Sin(ang); | ||
62 | float c = (float)Math.Cos(ang); | ||
63 | |||
64 | ori.X = 0; | ||
65 | ori.Y = 0; | ||
66 | ori.Z = s; | ||
67 | ori.W = c; | ||
68 | } | ||
69 | |||
55 | 70 | ||
56 | public void Sit(PhysicsActor actor, Vector3 avPos, Vector3 avCameraPosition, Vector3 offset, Vector3 avOffset, SitAvatarCallback PhysicsSitResponse) | 71 | public void Sit(PhysicsActor actor, Vector3 avPos, Vector3 avCameraPosition, Vector3 offset, Vector3 avOffset, SitAvatarCallback PhysicsSitResponse) |
57 | { | 72 | { |
@@ -63,88 +78,82 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
63 | 78 | ||
64 | IntPtr geom = ((OdePrim)actor).prim_geom; | 79 | IntPtr geom = ((OdePrim)actor).prim_geom; |
65 | 80 | ||
66 | d.Vector3 dtmp = d.GeomGetPosition(geom); | 81 | Vector3 geopos = d.GeomGetPositionOMV(geom); |
67 | Vector3 geopos; | 82 | Quaternion geomOri = d.GeomGetQuaternionOMV(geom); |
68 | geopos.X = dtmp.X; | 83 | Quaternion geomInvOri = Quaternion.Conjugate(geomOri); |
69 | geopos.Y = dtmp.Y; | 84 | |
70 | geopos.Z = dtmp.Z; | 85 | Quaternion ori = Quaternion.Identity; |
71 | 86 | ||
72 | 87 | Vector3 rayDir = geopos + offset - avCameraPosition; | |
73 | d.AABB aabb; | 88 | |
74 | Quaternion ori; | ||
75 | d.Quaternion qtmp; | ||
76 | d.GeomCopyQuaternion(geom, out qtmp); | ||
77 | Quaternion geomOri; | ||
78 | geomOri.X = qtmp.X; | ||
79 | geomOri.Y = qtmp.Y; | ||
80 | geomOri.Z = qtmp.Z; | ||
81 | geomOri.W = qtmp.W; | ||
82 | Quaternion geomInvOri; | ||
83 | geomInvOri.X = -qtmp.X; | ||
84 | geomInvOri.Y = -qtmp.Y; | ||
85 | geomInvOri.Z = -qtmp.Z; | ||
86 | geomInvOri.W = qtmp.W; | ||
87 | |||
88 | Vector3 target = geopos + offset; | ||
89 | Vector3 rayDir = target - avCameraPosition; | ||
90 | float raylen = rayDir.Length(); | 89 | float raylen = rayDir.Length(); |
90 | if (raylen < 0.001f) | ||
91 | { | ||
92 | PhysicsSitResponse(-1, actor.LocalID, offset, Quaternion.Identity); | ||
93 | return; | ||
94 | } | ||
91 | float t = 1 / raylen; | 95 | float t = 1 / raylen; |
92 | rayDir.X *= t; | 96 | rayDir.X *= t; |
93 | rayDir.Y *= t; | 97 | rayDir.Y *= t; |
94 | rayDir.Z *= t; | 98 | rayDir.Z *= t; |
95 | 99 | ||
96 | raylen += 0.5f; | 100 | raylen += 30f; // focal point may be far |
97 | List<ContactResult> rayResults; | 101 | List<ContactResult> rayResults; |
98 | 102 | ||
99 | rayResults = m_scene.RaycastActor(actor, avCameraPosition, rayDir , raylen, 1); | 103 | rayResults = m_scene.RaycastActor(actor, avCameraPosition, rayDir, raylen, 1, RaySitFlags); |
100 | if (rayResults.Count == 0 || rayResults[0].ConsumerID != actor.LocalID) | 104 | if (rayResults.Count == 0) |
101 | { | 105 | { |
102 | d.GeomGetAABB(geom,out aabb); | 106 | /* if this fundamental ray failed, then just fail so user can try another spot and not be sitted far on a big prim |
107 | d.AABB aabb; | ||
108 | d.GeomGetAABB(geom, out aabb); | ||
103 | offset = new Vector3(avOffset.X, 0, aabb.MaxZ + avOffset.Z - geopos.Z); | 109 | offset = new Vector3(avOffset.X, 0, aabb.MaxZ + avOffset.Z - geopos.Z); |
104 | ori = geomInvOri; | 110 | ori = geomInvOri; |
105 | offset *= geomInvOri; | 111 | offset *= geomInvOri; |
106 | |||
107 | PhysicsSitResponse(1, actor.LocalID, offset, ori); | 112 | PhysicsSitResponse(1, actor.LocalID, offset, ori); |
113 | */ | ||
114 | PhysicsSitResponse(0, actor.LocalID, offset, ori); | ||
108 | return; | 115 | return; |
109 | } | 116 | } |
110 | 117 | ||
118 | int status = 1; | ||
111 | offset = rayResults[0].Pos - geopos; | 119 | offset = rayResults[0].Pos - geopos; |
112 | double ang; | ||
113 | float s; | ||
114 | float c; | ||
115 | 120 | ||
116 | d.GeomClassID geoclass = d.GeomGetClass(geom); | 121 | d.GeomClassID geoclass = d.GeomGetClass(geom); |
117 | 122 | ||
118 | if (geoclass == d.GeomClassID.SphereClass) | 123 | if (geoclass == d.GeomClassID.SphereClass) |
119 | { | 124 | { |
120 | float r = d.GeomSphereGetRadius(geom); | 125 | float r = d.GeomSphereGetRadius(geom); |
121 | 126 | ||
122 | offset.Normalize(); | 127 | offset.Normalize(); |
123 | offset *= r; | 128 | offset *= r; |
124 | 129 | ||
125 | ang = Math.Atan2(offset.Y, offset.X); | 130 | RotAroundZ(offset.X, offset.Y, ref ori); |
126 | ang *= 0.5d; | ||
127 | s = (float)Math.Sin(ang); | ||
128 | c = (float)Math.Cos(ang); | ||
129 | |||
130 | ori = new Quaternion(0, 0, s, c); | ||
131 | 131 | ||
132 | if (r < 0.4f) | 132 | if (r < 0.4f) |
133 | { | 133 | { |
134 | offset = new Vector3(0, 0, r); | 134 | offset = new Vector3(0, 0, r); |
135 | } | 135 | } |
136 | else if (offset.Z < 0.4f) | 136 | else |
137 | { | 137 | { |
138 | t = offset.Z; | 138 | if (offset.Z < 0.4f) |
139 | float rsq = r * r; | 139 | { |
140 | 140 | t = offset.Z; | |
141 | t = 1.0f / (rsq - t * t); | 141 | float rsq = r * r; |
142 | offset.X *= t; | 142 | |
143 | offset.Y *= t; | 143 | t = 1.0f / (rsq - t * t); |
144 | offset.Z = 0.4f; | 144 | offset.X *= t; |
145 | t = rsq - 0.16f; | 145 | offset.Y *= t; |
146 | offset.X *= t; | 146 | offset.Z = 0.4f; |
147 | offset.Y *= t; | 147 | t = rsq - 0.16f; |
148 | offset.X *= t; | ||
149 | offset.Y *= t; | ||
150 | } | ||
151 | else if (r > 0.8f && offset.Z > 0.8f * r) | ||
152 | { | ||
153 | status = 3; | ||
154 | avOffset.X = -avOffset.X; | ||
155 | avOffset.Z *= 1.6f; | ||
156 | } | ||
148 | } | 157 | } |
149 | 158 | ||
150 | offset += avOffset * ori; | 159 | offset += avOffset * ori; |
@@ -152,26 +161,189 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
152 | ori = geomInvOri * ori; | 161 | ori = geomInvOri * ori; |
153 | offset *= geomInvOri; | 162 | offset *= geomInvOri; |
154 | 163 | ||
155 | PhysicsSitResponse(1, actor.LocalID, offset, ori); | 164 | PhysicsSitResponse(status, actor.LocalID, offset, ori); |
156 | return; | 165 | return; |
157 | } | 166 | } |
158 | 167 | ||
159 | Vector3 norm = rayResults[0].Normal; | 168 | Vector3 norm = rayResults[0].Normal; |
160 | 169 | ||
161 | if (norm.Z < 0) | 170 | if (norm.Z < -0.4f) |
162 | { | 171 | { |
163 | PhysicsSitResponse(0, actor.LocalID, offset, Quaternion.Identity); | 172 | PhysicsSitResponse(0, actor.LocalID, offset, Quaternion.Identity); |
164 | return; | 173 | return; |
165 | } | 174 | } |
166 | 175 | ||
167 | ang = Math.Atan2(-rayDir.Y, -rayDir.X); | ||
168 | ang *= 0.5d; | ||
169 | s = (float)Math.Sin(ang); | ||
170 | c = (float)Math.Cos(ang); | ||
171 | 176 | ||
172 | ori = new Quaternion(0, 0, s, c); | 177 | float SitNormX = -rayDir.X; |
178 | float SitNormY = -rayDir.Y; | ||
179 | |||
180 | Vector3 pivot = geopos + offset; | ||
181 | |||
182 | float edgeNormalX = norm.X; | ||
183 | float edgeNormalY = norm.Y; | ||
184 | float edgeDirX = -rayDir.X; | ||
185 | float edgeDirY = -rayDir.Y; | ||
186 | Vector3 edgePos = rayResults[0].Pos; | ||
187 | float edgeDist = float.MaxValue; | ||
188 | |||
189 | bool foundEdge = false; | ||
190 | |||
191 | if (norm.Z < 0.5f) | ||
192 | { | ||
193 | float rayDist = 4.0f; | ||
194 | float curEdgeDist = 0.0f; | ||
195 | |||
196 | for (int i = 0; i < 6; i++) | ||
197 | { | ||
198 | pivot.X -= 0.005f * norm.X; | ||
199 | pivot.Y -= 0.005f * norm.Y; | ||
200 | pivot.Z -= 0.005f * norm.Z; | ||
201 | |||
202 | rayDir.X = -norm.X * norm.Z; | ||
203 | rayDir.Y = -norm.Y * norm.Z; | ||
204 | rayDir.Z = 1.0f - norm.Z * norm.Z; | ||
205 | rayDir.Normalize(); | ||
206 | |||
207 | rayResults = m_scene.RaycastActor(actor, pivot, rayDir, rayDist, 1, RayFilterFlags.AllPrims); | ||
208 | if (rayResults.Count == 0) | ||
209 | break; | ||
210 | |||
211 | curEdgeDist += rayResults[0].Depth; | ||
212 | |||
213 | if (Math.Abs(rayResults[0].Normal.Z) < 0.7f) | ||
214 | { | ||
215 | rayDist -= rayResults[0].Depth; | ||
216 | if (rayDist < 0f) | ||
217 | break; | ||
218 | |||
219 | pivot = rayResults[0].Pos; | ||
220 | norm = rayResults[0].Normal; | ||
221 | edgeNormalX = norm.X; | ||
222 | edgeNormalY = norm.Y; | ||
223 | edgeDirX = -rayDir.X; | ||
224 | edgeDirY = -rayDir.Y; | ||
225 | } | ||
226 | else | ||
227 | { | ||
228 | foundEdge = true; | ||
229 | edgeDist = curEdgeDist; | ||
230 | edgePos = rayResults[0].Pos; | ||
231 | break; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | if (!foundEdge) | ||
236 | { | ||
237 | PhysicsSitResponse(0, actor.LocalID, offset, ori); | ||
238 | return; | ||
239 | } | ||
240 | avOffset.X *= 0.5f; | ||
241 | } | ||
242 | |||
243 | else if (norm.Z > 0.866f) | ||
244 | { | ||
245 | float toCamBaseX = avCameraPosition.X - pivot.X; | ||
246 | float toCamBaseY = avCameraPosition.Y - pivot.Y; | ||
247 | float toCamX = toCamBaseX; | ||
248 | float toCamY = toCamBaseY; | ||
249 | |||
250 | for (int j = 0; j < 4; j++) | ||
251 | { | ||
252 | float rayDist = 1.0f; | ||
253 | float curEdgeDist = 0.0f; | ||
254 | |||
255 | for (int i = 0; i < 3; i++) | ||
256 | { | ||
257 | pivot.Z -= 0.005f; | ||
258 | rayDir.X = toCamX; | ||
259 | rayDir.Y = toCamY; | ||
260 | rayDir.Z = (-toCamX * norm.X - toCamY * norm.Y) / norm.Z; | ||
261 | rayDir.Normalize(); | ||
262 | |||
263 | rayResults = m_scene.RaycastActor(actor, pivot, rayDir, rayDist, 1, RayFilterFlags.AllPrims); | ||
264 | if (rayResults.Count == 0) | ||
265 | break; | ||
266 | |||
267 | curEdgeDist += rayResults[0].Depth; | ||
268 | |||
269 | if (rayResults[0].Normal.Z > 0.5f) | ||
270 | { | ||
271 | rayDist -= rayResults[0].Depth; | ||
272 | if (rayDist < 0f) | ||
273 | break; | ||
274 | |||
275 | pivot = rayResults[0].Pos; | ||
276 | norm = rayResults[0].Normal; | ||
277 | } | ||
278 | else | ||
279 | { | ||
280 | foundEdge = true; | ||
281 | if (curEdgeDist < edgeDist) | ||
282 | { | ||
283 | edgeDist = curEdgeDist; | ||
284 | edgeNormalX = rayResults[0].Normal.X; | ||
285 | edgeNormalY = rayResults[0].Normal.Y; | ||
286 | edgeDirX = rayDir.X; | ||
287 | edgeDirY = rayDir.Y; | ||
288 | edgePos = rayResults[0].Pos; | ||
289 | } | ||
290 | break; | ||
291 | } | ||
292 | } | ||
293 | if (foundEdge && edgeDist < 0.2f) | ||
294 | break; | ||
295 | |||
296 | pivot = geopos + offset; | ||
297 | |||
298 | switch (j) | ||
299 | { | ||
300 | case 0: | ||
301 | toCamX = -toCamBaseY; | ||
302 | toCamY = toCamBaseX; | ||
303 | break; | ||
304 | case 1: | ||
305 | toCamX = toCamBaseY; | ||
306 | toCamY = -toCamBaseX; | ||
307 | break; | ||
308 | case 2: | ||
309 | toCamX = -toCamBaseX; | ||
310 | toCamY = -toCamBaseY; | ||
311 | break; | ||
312 | default: | ||
313 | break; | ||
314 | } | ||
315 | } | ||
316 | |||
317 | if (!foundEdge) | ||
318 | { | ||
319 | avOffset.X = -avOffset.X; | ||
320 | avOffset.Z *= 1.6f; | ||
321 | |||
322 | RotAroundZ(SitNormX, SitNormY, ref ori); | ||
323 | |||
324 | offset += avOffset * ori; | ||
325 | |||
326 | ori = geomInvOri * ori; | ||
327 | offset *= geomInvOri; | ||
328 | |||
329 | PhysicsSitResponse(3, actor.LocalID, offset, ori); | ||
330 | return; | ||
331 | } | ||
332 | avOffset.X *= 0.5f; | ||
333 | } | ||
334 | |||
335 | SitNormX = edgeNormalX; | ||
336 | SitNormY = edgeNormalY; | ||
337 | if (edgeDirX * SitNormX + edgeDirY * SitNormY < 0) | ||
338 | { | ||
339 | SitNormX = -SitNormX; | ||
340 | SitNormY = -SitNormY; | ||
341 | } | ||
342 | |||
343 | RotAroundZ(SitNormX, SitNormY, ref ori); | ||
173 | 344 | ||
174 | offset += avOffset * ori; | 345 | offset = edgePos + avOffset * ori; |
346 | offset -= geopos; | ||
175 | 347 | ||
176 | ori = geomInvOri * ori; | 348 | ori = geomInvOri * ori; |
177 | offset *= geomInvOri; | 349 | offset *= geomInvOri; |