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