diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/CSceneCollisionManager.cpp | 1920 |
1 files changed, 960 insertions, 960 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CSceneCollisionManager.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CSceneCollisionManager.cpp index cda4133..b3895bc 100644 --- a/libraries/irrlicht-1.8/source/Irrlicht/CSceneCollisionManager.cpp +++ b/libraries/irrlicht-1.8/source/Irrlicht/CSceneCollisionManager.cpp | |||
@@ -1,960 +1,960 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt | 1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt |
2 | // This file is part of the "Irrlicht Engine". | 2 | // This file is part of the "Irrlicht Engine". |
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | 3 | // For conditions of distribution and use, see copyright notice in irrlicht.h |
4 | 4 | ||
5 | #include "CSceneCollisionManager.h" | 5 | #include "CSceneCollisionManager.h" |
6 | #include "ISceneNode.h" | 6 | #include "ISceneNode.h" |
7 | #include "ICameraSceneNode.h" | 7 | #include "ICameraSceneNode.h" |
8 | #include "ITriangleSelector.h" | 8 | #include "ITriangleSelector.h" |
9 | #include "SViewFrustum.h" | 9 | #include "SViewFrustum.h" |
10 | 10 | ||
11 | #include "os.h" | 11 | #include "os.h" |
12 | #include "irrMath.h" | 12 | #include "irrMath.h" |
13 | 13 | ||
14 | namespace irr | 14 | namespace irr |
15 | { | 15 | { |
16 | namespace scene | 16 | namespace scene |
17 | { | 17 | { |
18 | 18 | ||
19 | //! constructor | 19 | //! constructor |
20 | CSceneCollisionManager::CSceneCollisionManager(ISceneManager* smanager, video::IVideoDriver* driver) | 20 | CSceneCollisionManager::CSceneCollisionManager(ISceneManager* smanager, video::IVideoDriver* driver) |
21 | : SceneManager(smanager), Driver(driver) | 21 | : SceneManager(smanager), Driver(driver) |
22 | { | 22 | { |
23 | #ifdef _DEBUG | 23 | #ifdef _DEBUG |
24 | setDebugName("CSceneCollisionManager"); | 24 | setDebugName("CSceneCollisionManager"); |
25 | #endif | 25 | #endif |
26 | 26 | ||
27 | if (Driver) | 27 | if (Driver) |
28 | Driver->grab(); | 28 | Driver->grab(); |
29 | } | 29 | } |
30 | 30 | ||
31 | 31 | ||
32 | //! destructor | 32 | //! destructor |
33 | CSceneCollisionManager::~CSceneCollisionManager() | 33 | CSceneCollisionManager::~CSceneCollisionManager() |
34 | { | 34 | { |
35 | if (Driver) | 35 | if (Driver) |
36 | Driver->drop(); | 36 | Driver->drop(); |
37 | } | 37 | } |
38 | 38 | ||
39 | 39 | ||
40 | //! Returns the scene node, which is currently visible at the given | 40 | //! Returns the scene node, which is currently visible at the given |
41 | //! screen coordinates, viewed from the currently active camera. | 41 | //! screen coordinates, viewed from the currently active camera. |
42 | ISceneNode* CSceneCollisionManager::getSceneNodeFromScreenCoordinatesBB( | 42 | ISceneNode* CSceneCollisionManager::getSceneNodeFromScreenCoordinatesBB( |
43 | const core::position2d<s32>& pos, s32 idBitMask, bool noDebugObjects, scene::ISceneNode* root) | 43 | const core::position2d<s32>& pos, s32 idBitMask, bool noDebugObjects, scene::ISceneNode* root) |
44 | { | 44 | { |
45 | const core::line3d<f32> ln = getRayFromScreenCoordinates(pos, 0); | 45 | const core::line3d<f32> ln = getRayFromScreenCoordinates(pos, 0); |
46 | 46 | ||
47 | if ( ln.start == ln.end ) | 47 | if ( ln.start == ln.end ) |
48 | return 0; | 48 | return 0; |
49 | 49 | ||
50 | return getSceneNodeFromRayBB(ln, idBitMask, noDebugObjects, root); | 50 | return getSceneNodeFromRayBB(ln, idBitMask, noDebugObjects, root); |
51 | } | 51 | } |
52 | 52 | ||
53 | 53 | ||
54 | //! Returns the nearest scene node which collides with a 3d ray and | 54 | //! Returns the nearest scene node which collides with a 3d ray and |
55 | //! which id matches a bitmask. | 55 | //! which id matches a bitmask. |
56 | ISceneNode* CSceneCollisionManager::getSceneNodeFromRayBB( | 56 | ISceneNode* CSceneCollisionManager::getSceneNodeFromRayBB( |
57 | const core::line3d<f32>& ray, | 57 | const core::line3d<f32>& ray, |
58 | s32 idBitMask, bool noDebugObjects, scene::ISceneNode* root) | 58 | s32 idBitMask, bool noDebugObjects, scene::ISceneNode* root) |
59 | { | 59 | { |
60 | ISceneNode* best = 0; | 60 | ISceneNode* best = 0; |
61 | f32 dist = FLT_MAX; | 61 | f32 dist = FLT_MAX; |
62 | 62 | ||
63 | core::line3d<f32> truncatableRay(ray); | 63 | core::line3d<f32> truncatableRay(ray); |
64 | 64 | ||
65 | getPickedNodeBB((root==0)?SceneManager->getRootSceneNode():root, truncatableRay, | 65 | getPickedNodeBB((root==0)?SceneManager->getRootSceneNode():root, truncatableRay, |
66 | idBitMask, noDebugObjects, dist, best); | 66 | idBitMask, noDebugObjects, dist, best); |
67 | 67 | ||
68 | return best; | 68 | return best; |
69 | } | 69 | } |
70 | 70 | ||
71 | 71 | ||
72 | //! recursive method for going through all scene nodes | 72 | //! recursive method for going through all scene nodes |
73 | void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root, | 73 | void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root, |
74 | core::line3df& ray, s32 bits, bool noDebugObjects, | 74 | core::line3df& ray, s32 bits, bool noDebugObjects, |
75 | f32& outbestdistance, ISceneNode*& outbestnode) | 75 | f32& outbestdistance, ISceneNode*& outbestnode) |
76 | { | 76 | { |
77 | const ISceneNodeList& children = root->getChildren(); | 77 | const ISceneNodeList& children = root->getChildren(); |
78 | const core::vector3df rayVector = ray.getVector().normalize(); | 78 | const core::vector3df rayVector = ray.getVector().normalize(); |
79 | 79 | ||
80 | ISceneNodeList::ConstIterator it = children.begin(); | 80 | ISceneNodeList::ConstIterator it = children.begin(); |
81 | for (; it != children.end(); ++it) | 81 | for (; it != children.end(); ++it) |
82 | { | 82 | { |
83 | ISceneNode* current = *it; | 83 | ISceneNode* current = *it; |
84 | 84 | ||
85 | if (current->isVisible()) | 85 | if (current->isVisible()) |
86 | { | 86 | { |
87 | if((noDebugObjects ? !current->isDebugObject() : true) && | 87 | if((noDebugObjects ? !current->isDebugObject() : true) && |
88 | (bits==0 || (bits != 0 && (current->getID() & bits)))) | 88 | (bits==0 || (bits != 0 && (current->getID() & bits)))) |
89 | { | 89 | { |
90 | // get world to object space transform | 90 | // get world to object space transform |
91 | core::matrix4 worldToObject; | 91 | core::matrix4 worldToObject; |
92 | if (!current->getAbsoluteTransformation().getInverse(worldToObject)) | 92 | if (!current->getAbsoluteTransformation().getInverse(worldToObject)) |
93 | continue; | 93 | continue; |
94 | 94 | ||
95 | // transform vector from world space to object space | 95 | // transform vector from world space to object space |
96 | core::line3df objectRay(ray); | 96 | core::line3df objectRay(ray); |
97 | worldToObject.transformVect(objectRay.start); | 97 | worldToObject.transformVect(objectRay.start); |
98 | worldToObject.transformVect(objectRay.end); | 98 | worldToObject.transformVect(objectRay.end); |
99 | 99 | ||
100 | const core::aabbox3df & objectBox = current->getBoundingBox(); | 100 | const core::aabbox3df & objectBox = current->getBoundingBox(); |
101 | 101 | ||
102 | // Do the initial intersection test in object space, since the | 102 | // Do the initial intersection test in object space, since the |
103 | // object space box test is more accurate. | 103 | // object space box test is more accurate. |
104 | if(objectBox.isPointInside(objectRay.start)) | 104 | if(objectBox.isPointInside(objectRay.start)) |
105 | { | 105 | { |
106 | // use fast bbox intersection to find distance to hitpoint | 106 | // use fast bbox intersection to find distance to hitpoint |
107 | // algorithm from Kay et al., code from gamedev.net | 107 | // algorithm from Kay et al., code from gamedev.net |
108 | const core::vector3df dir = (objectRay.end-objectRay.start).normalize(); | 108 | const core::vector3df dir = (objectRay.end-objectRay.start).normalize(); |
109 | const core::vector3df minDist = (objectBox.MinEdge - objectRay.start)/dir; | 109 | const core::vector3df minDist = (objectBox.MinEdge - objectRay.start)/dir; |
110 | const core::vector3df maxDist = (objectBox.MaxEdge - objectRay.start)/dir; | 110 | const core::vector3df maxDist = (objectBox.MaxEdge - objectRay.start)/dir; |
111 | const core::vector3df realMin(core::min_(minDist.X, maxDist.X),core::min_(minDist.Y, maxDist.Y),core::min_(minDist.Z, maxDist.Z)); | 111 | const core::vector3df realMin(core::min_(minDist.X, maxDist.X),core::min_(minDist.Y, maxDist.Y),core::min_(minDist.Z, maxDist.Z)); |
112 | const core::vector3df realMax(core::max_(minDist.X, maxDist.X),core::max_(minDist.Y, maxDist.Y),core::max_(minDist.Z, maxDist.Z)); | 112 | const core::vector3df realMax(core::max_(minDist.X, maxDist.X),core::max_(minDist.Y, maxDist.Y),core::max_(minDist.Z, maxDist.Z)); |
113 | 113 | ||
114 | const f32 minmax = core::min_(realMax.X, realMax.Y, realMax.Z); | 114 | const f32 minmax = core::min_(realMax.X, realMax.Y, realMax.Z); |
115 | // nearest distance to intersection | 115 | // nearest distance to intersection |
116 | const f32 maxmin = core::max_(realMin.X, realMin.Y, realMin.Z); | 116 | const f32 maxmin = core::max_(realMin.X, realMin.Y, realMin.Z); |
117 | 117 | ||
118 | const f32 toIntersectionSq = (maxmin>0?maxmin*maxmin:minmax*minmax); | 118 | const f32 toIntersectionSq = (maxmin>0?maxmin*maxmin:minmax*minmax); |
119 | if (toIntersectionSq < outbestdistance) | 119 | if (toIntersectionSq < outbestdistance) |
120 | { | 120 | { |
121 | outbestdistance = toIntersectionSq; | 121 | outbestdistance = toIntersectionSq; |
122 | outbestnode = current; | 122 | outbestnode = current; |
123 | 123 | ||
124 | // And we can truncate the ray to stop us hitting further nodes. | 124 | // And we can truncate the ray to stop us hitting further nodes. |
125 | ray.end = ray.start + (rayVector * sqrtf(toIntersectionSq)); | 125 | ray.end = ray.start + (rayVector * sqrtf(toIntersectionSq)); |
126 | } | 126 | } |
127 | } | 127 | } |
128 | else | 128 | else |
129 | if (objectBox.intersectsWithLine(objectRay)) | 129 | if (objectBox.intersectsWithLine(objectRay)) |
130 | { | 130 | { |
131 | // Now transform into world space, since we need to use world space | 131 | // Now transform into world space, since we need to use world space |
132 | // scales and distances. | 132 | // scales and distances. |
133 | core::aabbox3df worldBox(objectBox); | 133 | core::aabbox3df worldBox(objectBox); |
134 | current->getAbsoluteTransformation().transformBox(worldBox); | 134 | current->getAbsoluteTransformation().transformBox(worldBox); |
135 | 135 | ||
136 | core::vector3df edges[8]; | 136 | core::vector3df edges[8]; |
137 | worldBox.getEdges(edges); | 137 | worldBox.getEdges(edges); |
138 | 138 | ||
139 | /* We need to check against each of 6 faces, composed of these corners: | 139 | /* We need to check against each of 6 faces, composed of these corners: |
140 | /3--------/7 | 140 | /3--------/7 |
141 | / | / | | 141 | / | / | |
142 | / | / | | 142 | / | / | |
143 | 1---------5 | | 143 | 1---------5 | |
144 | | 2- - -| -6 | 144 | | 2- - -| -6 |
145 | | / | / | 145 | | / | / |
146 | |/ | / | 146 | |/ | / |
147 | 0---------4/ | 147 | 0---------4/ |
148 | 148 | ||
149 | Note that we define them as opposite pairs of faces. | 149 | Note that we define them as opposite pairs of faces. |
150 | */ | 150 | */ |
151 | static const s32 faceEdges[6][3] = | 151 | static const s32 faceEdges[6][3] = |
152 | { | 152 | { |
153 | { 0, 1, 5 }, // Front | 153 | { 0, 1, 5 }, // Front |
154 | { 6, 7, 3 }, // Back | 154 | { 6, 7, 3 }, // Back |
155 | { 2, 3, 1 }, // Left | 155 | { 2, 3, 1 }, // Left |
156 | { 4, 5, 7 }, // Right | 156 | { 4, 5, 7 }, // Right |
157 | { 1, 3, 7 }, // Top | 157 | { 1, 3, 7 }, // Top |
158 | { 2, 0, 4 } // Bottom | 158 | { 2, 0, 4 } // Bottom |
159 | }; | 159 | }; |
160 | 160 | ||
161 | core::vector3df intersection; | 161 | core::vector3df intersection; |
162 | core::plane3df facePlane; | 162 | core::plane3df facePlane; |
163 | f32 bestDistToBoxBorder = FLT_MAX; | 163 | f32 bestDistToBoxBorder = FLT_MAX; |
164 | f32 bestToIntersectionSq = FLT_MAX; | 164 | f32 bestToIntersectionSq = FLT_MAX; |
165 | 165 | ||
166 | for(s32 face = 0; face < 6; ++face) | 166 | for(s32 face = 0; face < 6; ++face) |
167 | { | 167 | { |
168 | facePlane.setPlane(edges[faceEdges[face][0]], | 168 | facePlane.setPlane(edges[faceEdges[face][0]], |
169 | edges[faceEdges[face][1]], | 169 | edges[faceEdges[face][1]], |
170 | edges[faceEdges[face][2]]); | 170 | edges[faceEdges[face][2]]); |
171 | 171 | ||
172 | // Only consider lines that might be entering through this face, since we | 172 | // Only consider lines that might be entering through this face, since we |
173 | // already know that the start point is outside the box. | 173 | // already know that the start point is outside the box. |
174 | if(facePlane.classifyPointRelation(ray.start) != core::ISREL3D_FRONT) | 174 | if(facePlane.classifyPointRelation(ray.start) != core::ISREL3D_FRONT) |
175 | continue; | 175 | continue; |
176 | 176 | ||
177 | // Don't bother using a limited ray, since we already know that it should be long | 177 | // Don't bother using a limited ray, since we already know that it should be long |
178 | // enough to intersect with the box. | 178 | // enough to intersect with the box. |
179 | if(facePlane.getIntersectionWithLine(ray.start, rayVector, intersection)) | 179 | if(facePlane.getIntersectionWithLine(ray.start, rayVector, intersection)) |
180 | { | 180 | { |
181 | const f32 toIntersectionSq = ray.start.getDistanceFromSQ(intersection); | 181 | const f32 toIntersectionSq = ray.start.getDistanceFromSQ(intersection); |
182 | if(toIntersectionSq < outbestdistance) | 182 | if(toIntersectionSq < outbestdistance) |
183 | { | 183 | { |
184 | // We have to check that the intersection with this plane is actually | 184 | // We have to check that the intersection with this plane is actually |
185 | // on the box, so need to go back to object space again. | 185 | // on the box, so need to go back to object space again. |
186 | worldToObject.transformVect(intersection); | 186 | worldToObject.transformVect(intersection); |
187 | 187 | ||
188 | // find the closest point on the box borders. Have to do this as exact checks will fail due to floating point problems. | 188 | // find the closest point on the box borders. Have to do this as exact checks will fail due to floating point problems. |
189 | f32 distToBorder = core::max_ ( core::min_ (core::abs_(objectBox.MinEdge.X-intersection.X), core::abs_(objectBox.MaxEdge.X-intersection.X)), | 189 | f32 distToBorder = core::max_ ( core::min_ (core::abs_(objectBox.MinEdge.X-intersection.X), core::abs_(objectBox.MaxEdge.X-intersection.X)), |
190 | core::min_ (core::abs_(objectBox.MinEdge.Y-intersection.Y), core::abs_(objectBox.MaxEdge.Y-intersection.Y)), | 190 | core::min_ (core::abs_(objectBox.MinEdge.Y-intersection.Y), core::abs_(objectBox.MaxEdge.Y-intersection.Y)), |
191 | core::min_ (core::abs_(objectBox.MinEdge.Z-intersection.Z), core::abs_(objectBox.MaxEdge.Z-intersection.Z)) ); | 191 | core::min_ (core::abs_(objectBox.MinEdge.Z-intersection.Z), core::abs_(objectBox.MaxEdge.Z-intersection.Z)) ); |
192 | if ( distToBorder < bestDistToBoxBorder ) | 192 | if ( distToBorder < bestDistToBoxBorder ) |
193 | { | 193 | { |
194 | bestDistToBoxBorder = distToBorder; | 194 | bestDistToBoxBorder = distToBorder; |
195 | bestToIntersectionSq = toIntersectionSq; | 195 | bestToIntersectionSq = toIntersectionSq; |
196 | } | 196 | } |
197 | } | 197 | } |
198 | } | 198 | } |
199 | 199 | ||
200 | // If the ray could be entering through the first face of a pair, then it can't | 200 | // If the ray could be entering through the first face of a pair, then it can't |
201 | // also be entering through the opposite face, and so we can skip that face. | 201 | // also be entering through the opposite face, and so we can skip that face. |
202 | if (!(face & 0x01)) | 202 | if (!(face & 0x01)) |
203 | ++face; | 203 | ++face; |
204 | } | 204 | } |
205 | 205 | ||
206 | if ( bestDistToBoxBorder < FLT_MAX ) | 206 | if ( bestDistToBoxBorder < FLT_MAX ) |
207 | { | 207 | { |
208 | outbestdistance = bestToIntersectionSq; | 208 | outbestdistance = bestToIntersectionSq; |
209 | outbestnode = current; | 209 | outbestnode = current; |
210 | 210 | ||
211 | // If we got a hit, we can now truncate the ray to stop us hitting further nodes. | 211 | // If we got a hit, we can now truncate the ray to stop us hitting further nodes. |
212 | ray.end = ray.start + (rayVector * sqrtf(outbestdistance)); | 212 | ray.end = ray.start + (rayVector * sqrtf(outbestdistance)); |
213 | } | 213 | } |
214 | } | 214 | } |
215 | } | 215 | } |
216 | 216 | ||
217 | // Only check the children if this node is visible. | 217 | // Only check the children if this node is visible. |
218 | getPickedNodeBB(current, ray, bits, noDebugObjects, outbestdistance, outbestnode); | 218 | getPickedNodeBB(current, ray, bits, noDebugObjects, outbestdistance, outbestnode); |
219 | } | 219 | } |
220 | } | 220 | } |
221 | } | 221 | } |
222 | 222 | ||
223 | 223 | ||
224 | ISceneNode* CSceneCollisionManager::getSceneNodeAndCollisionPointFromRay( | 224 | ISceneNode* CSceneCollisionManager::getSceneNodeAndCollisionPointFromRay( |
225 | core::line3df ray, | 225 | core::line3df ray, |
226 | core::vector3df & outCollisionPoint, | 226 | core::vector3df & outCollisionPoint, |
227 | core::triangle3df & outTriangle, | 227 | core::triangle3df & outTriangle, |
228 | s32 idBitMask, | 228 | s32 idBitMask, |
229 | ISceneNode * collisionRootNode, | 229 | ISceneNode * collisionRootNode, |
230 | bool noDebugObjects) | 230 | bool noDebugObjects) |
231 | { | 231 | { |
232 | ISceneNode* bestNode = 0; | 232 | ISceneNode* bestNode = 0; |
233 | f32 bestDistanceSquared = FLT_MAX; | 233 | f32 bestDistanceSquared = FLT_MAX; |
234 | 234 | ||
235 | if(0 == collisionRootNode) | 235 | if(0 == collisionRootNode) |
236 | collisionRootNode = SceneManager->getRootSceneNode(); | 236 | collisionRootNode = SceneManager->getRootSceneNode(); |
237 | 237 | ||
238 | // We don't try to do anything too clever, like sorting the candidate | 238 | // We don't try to do anything too clever, like sorting the candidate |
239 | // nodes by distance to bounding-box. In the example below, we could do the | 239 | // nodes by distance to bounding-box. In the example below, we could do the |
240 | // triangle collision check with node A first, but we'd have to check node B | 240 | // triangle collision check with node A first, but we'd have to check node B |
241 | // anyway, as the actual collision point could be (and is) closer than the | 241 | // anyway, as the actual collision point could be (and is) closer than the |
242 | // collision point in node A. | 242 | // collision point in node A. |
243 | // | 243 | // |
244 | // ray end | 244 | // ray end |
245 | // | | 245 | // | |
246 | // AAAAAAAAAA | 246 | // AAAAAAAAAA |
247 | // A | | 247 | // A | |
248 | // A | B | 248 | // A | B |
249 | // A | B | 249 | // A | B |
250 | // A BBBBB | 250 | // A BBBBB |
251 | // A | | 251 | // A | |
252 | // A | | 252 | // A | |
253 | // | | 253 | // | |
254 | // | | 254 | // | |
255 | // ray start | 255 | // ray start |
256 | // | 256 | // |
257 | // We therefore have to do a full BB and triangle collision on every scene | 257 | // We therefore have to do a full BB and triangle collision on every scene |
258 | // node in order to find the nearest collision point, so sorting them by | 258 | // node in order to find the nearest collision point, so sorting them by |
259 | // bounding box would be pointless. | 259 | // bounding box would be pointless. |
260 | 260 | ||
261 | getPickedNodeFromBBAndSelector(collisionRootNode, ray, idBitMask, | 261 | getPickedNodeFromBBAndSelector(collisionRootNode, ray, idBitMask, |
262 | noDebugObjects, bestDistanceSquared, bestNode, | 262 | noDebugObjects, bestDistanceSquared, bestNode, |
263 | outCollisionPoint, outTriangle); | 263 | outCollisionPoint, outTriangle); |
264 | return bestNode; | 264 | return bestNode; |
265 | } | 265 | } |
266 | 266 | ||
267 | 267 | ||
268 | void CSceneCollisionManager::getPickedNodeFromBBAndSelector( | 268 | void CSceneCollisionManager::getPickedNodeFromBBAndSelector( |
269 | ISceneNode * root, | 269 | ISceneNode * root, |
270 | core::line3df & ray, | 270 | core::line3df & ray, |
271 | s32 bits, | 271 | s32 bits, |
272 | bool noDebugObjects, | 272 | bool noDebugObjects, |
273 | f32 & outBestDistanceSquared, | 273 | f32 & outBestDistanceSquared, |
274 | ISceneNode * & outBestNode, | 274 | ISceneNode * & outBestNode, |
275 | core::vector3df & outBestCollisionPoint, | 275 | core::vector3df & outBestCollisionPoint, |
276 | core::triangle3df & outBestTriangle) | 276 | core::triangle3df & outBestTriangle) |
277 | { | 277 | { |
278 | const ISceneNodeList& children = root->getChildren(); | 278 | const ISceneNodeList& children = root->getChildren(); |
279 | 279 | ||
280 | ISceneNodeList::ConstIterator it = children.begin(); | 280 | ISceneNodeList::ConstIterator it = children.begin(); |
281 | for (; it != children.end(); ++it) | 281 | for (; it != children.end(); ++it) |
282 | { | 282 | { |
283 | ISceneNode* current = *it; | 283 | ISceneNode* current = *it; |
284 | ITriangleSelector * selector = current->getTriangleSelector(); | 284 | ITriangleSelector * selector = current->getTriangleSelector(); |
285 | 285 | ||
286 | if (selector && current->isVisible() && | 286 | if (selector && current->isVisible() && |
287 | (noDebugObjects ? !current->isDebugObject() : true) && | 287 | (noDebugObjects ? !current->isDebugObject() : true) && |
288 | (bits==0 || (bits != 0 && (current->getID() & bits)))) | 288 | (bits==0 || (bits != 0 && (current->getID() & bits)))) |
289 | { | 289 | { |
290 | // get world to object space transform | 290 | // get world to object space transform |
291 | core::matrix4 mat; | 291 | core::matrix4 mat; |
292 | if (!current->getAbsoluteTransformation().getInverse(mat)) | 292 | if (!current->getAbsoluteTransformation().getInverse(mat)) |
293 | continue; | 293 | continue; |
294 | 294 | ||
295 | // transform vector from world space to object space | 295 | // transform vector from world space to object space |
296 | core::line3df line(ray); | 296 | core::line3df line(ray); |
297 | mat.transformVect(line.start); | 297 | mat.transformVect(line.start); |
298 | mat.transformVect(line.end); | 298 | mat.transformVect(line.end); |
299 | 299 | ||
300 | const core::aabbox3df& box = current->getBoundingBox(); | 300 | const core::aabbox3df& box = current->getBoundingBox(); |
301 | 301 | ||
302 | core::vector3df candidateCollisionPoint; | 302 | core::vector3df candidateCollisionPoint; |
303 | core::triangle3df candidateTriangle; | 303 | core::triangle3df candidateTriangle; |
304 | 304 | ||
305 | // do intersection test in object space | 305 | // do intersection test in object space |
306 | ISceneNode * hitNode = 0; | 306 | ISceneNode * hitNode = 0; |
307 | if (box.intersectsWithLine(line) && | 307 | if (box.intersectsWithLine(line) && |
308 | getCollisionPoint(ray, selector, candidateCollisionPoint, candidateTriangle, hitNode)) | 308 | getCollisionPoint(ray, selector, candidateCollisionPoint, candidateTriangle, hitNode)) |
309 | { | 309 | { |
310 | const f32 distanceSquared = (candidateCollisionPoint - ray.start).getLengthSQ(); | 310 | const f32 distanceSquared = (candidateCollisionPoint - ray.start).getLengthSQ(); |
311 | 311 | ||
312 | if(distanceSquared < outBestDistanceSquared) | 312 | if(distanceSquared < outBestDistanceSquared) |
313 | { | 313 | { |
314 | outBestDistanceSquared = distanceSquared; | 314 | outBestDistanceSquared = distanceSquared; |
315 | outBestNode = current; | 315 | outBestNode = current; |
316 | outBestCollisionPoint = candidateCollisionPoint; | 316 | outBestCollisionPoint = candidateCollisionPoint; |
317 | outBestTriangle = candidateTriangle; | 317 | outBestTriangle = candidateTriangle; |
318 | const core::vector3df rayVector = ray.getVector().normalize(); | 318 | const core::vector3df rayVector = ray.getVector().normalize(); |
319 | ray.end = ray.start + (rayVector * sqrtf(distanceSquared)); | 319 | ray.end = ray.start + (rayVector * sqrtf(distanceSquared)); |
320 | } | 320 | } |
321 | } | 321 | } |
322 | } | 322 | } |
323 | 323 | ||
324 | getPickedNodeFromBBAndSelector(current, ray, bits, noDebugObjects, | 324 | getPickedNodeFromBBAndSelector(current, ray, bits, noDebugObjects, |
325 | outBestDistanceSquared, outBestNode, | 325 | outBestDistanceSquared, outBestNode, |
326 | outBestCollisionPoint, outBestTriangle); | 326 | outBestCollisionPoint, outBestTriangle); |
327 | } | 327 | } |
328 | } | 328 | } |
329 | 329 | ||
330 | 330 | ||
331 | //! Returns the scene node, at which the overgiven camera is looking at and | 331 | //! Returns the scene node, at which the overgiven camera is looking at and |
332 | //! which id matches the bitmask. | 332 | //! which id matches the bitmask. |
333 | ISceneNode* CSceneCollisionManager::getSceneNodeFromCameraBB( | 333 | ISceneNode* CSceneCollisionManager::getSceneNodeFromCameraBB( |
334 | ICameraSceneNode* camera, s32 idBitMask, bool noDebugObjects) | 334 | ICameraSceneNode* camera, s32 idBitMask, bool noDebugObjects) |
335 | { | 335 | { |
336 | if (!camera) | 336 | if (!camera) |
337 | return 0; | 337 | return 0; |
338 | 338 | ||
339 | const core::vector3df start = camera->getAbsolutePosition(); | 339 | const core::vector3df start = camera->getAbsolutePosition(); |
340 | core::vector3df end = camera->getTarget(); | 340 | core::vector3df end = camera->getTarget(); |
341 | 341 | ||
342 | end = start + ((end - start).normalize() * camera->getFarValue()); | 342 | end = start + ((end - start).normalize() * camera->getFarValue()); |
343 | 343 | ||
344 | return getSceneNodeFromRayBB(core::line3d<f32>(start, end), idBitMask, noDebugObjects); | 344 | return getSceneNodeFromRayBB(core::line3d<f32>(start, end), idBitMask, noDebugObjects); |
345 | } | 345 | } |
346 | 346 | ||
347 | 347 | ||
348 | //! Finds the collision point of a line and lots of triangles, if there is one. | 348 | //! Finds the collision point of a line and lots of triangles, if there is one. |
349 | bool CSceneCollisionManager::getCollisionPoint(const core::line3d<f32>& ray, | 349 | bool CSceneCollisionManager::getCollisionPoint(const core::line3d<f32>& ray, |
350 | ITriangleSelector* selector, core::vector3df& outIntersection, | 350 | ITriangleSelector* selector, core::vector3df& outIntersection, |
351 | core::triangle3df& outTriangle, | 351 | core::triangle3df& outTriangle, |
352 | ISceneNode*& outNode) | 352 | ISceneNode*& outNode) |
353 | { | 353 | { |
354 | if (!selector) | 354 | if (!selector) |
355 | { | 355 | { |
356 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | 356 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; |
357 | return false; | 357 | return false; |
358 | } | 358 | } |
359 | 359 | ||
360 | s32 totalcnt = selector->getTriangleCount(); | 360 | s32 totalcnt = selector->getTriangleCount(); |
361 | if ( totalcnt <= 0 ) | 361 | if ( totalcnt <= 0 ) |
362 | return false; | 362 | return false; |
363 | 363 | ||
364 | Triangles.set_used(totalcnt); | 364 | Triangles.set_used(totalcnt); |
365 | 365 | ||
366 | s32 cnt = 0; | 366 | s32 cnt = 0; |
367 | selector->getTriangles(Triangles.pointer(), totalcnt, cnt, ray); | 367 | selector->getTriangles(Triangles.pointer(), totalcnt, cnt, ray); |
368 | 368 | ||
369 | const core::vector3df linevect = ray.getVector().normalize(); | 369 | const core::vector3df linevect = ray.getVector().normalize(); |
370 | core::vector3df intersection; | 370 | core::vector3df intersection; |
371 | f32 nearest = FLT_MAX; | 371 | f32 nearest = FLT_MAX; |
372 | bool found = false; | 372 | bool found = false; |
373 | const f32 raylength = ray.getLengthSQ(); | 373 | const f32 raylength = ray.getLengthSQ(); |
374 | 374 | ||
375 | const f32 minX = core::min_(ray.start.X, ray.end.X); | 375 | const f32 minX = core::min_(ray.start.X, ray.end.X); |
376 | const f32 maxX = core::max_(ray.start.X, ray.end.X); | 376 | const f32 maxX = core::max_(ray.start.X, ray.end.X); |
377 | const f32 minY = core::min_(ray.start.Y, ray.end.Y); | 377 | const f32 minY = core::min_(ray.start.Y, ray.end.Y); |
378 | const f32 maxY = core::max_(ray.start.Y, ray.end.Y); | 378 | const f32 maxY = core::max_(ray.start.Y, ray.end.Y); |
379 | const f32 minZ = core::min_(ray.start.Z, ray.end.Z); | 379 | const f32 minZ = core::min_(ray.start.Z, ray.end.Z); |
380 | const f32 maxZ = core::max_(ray.start.Z, ray.end.Z); | 380 | const f32 maxZ = core::max_(ray.start.Z, ray.end.Z); |
381 | 381 | ||
382 | for (s32 i=0; i<cnt; ++i) | 382 | for (s32 i=0; i<cnt; ++i) |
383 | { | 383 | { |
384 | const core::triangle3df & triangle = Triangles[i]; | 384 | const core::triangle3df & triangle = Triangles[i]; |
385 | 385 | ||
386 | if(minX > triangle.pointA.X && minX > triangle.pointB.X && minX > triangle.pointC.X) | 386 | if(minX > triangle.pointA.X && minX > triangle.pointB.X && minX > triangle.pointC.X) |
387 | continue; | 387 | continue; |
388 | if(maxX < triangle.pointA.X && maxX < triangle.pointB.X && maxX < triangle.pointC.X) | 388 | if(maxX < triangle.pointA.X && maxX < triangle.pointB.X && maxX < triangle.pointC.X) |
389 | continue; | 389 | continue; |
390 | if(minY > triangle.pointA.Y && minY > triangle.pointB.Y && minY > triangle.pointC.Y) | 390 | if(minY > triangle.pointA.Y && minY > triangle.pointB.Y && minY > triangle.pointC.Y) |
391 | continue; | 391 | continue; |
392 | if(maxY < triangle.pointA.Y && maxY < triangle.pointB.Y && maxY < triangle.pointC.Y) | 392 | if(maxY < triangle.pointA.Y && maxY < triangle.pointB.Y && maxY < triangle.pointC.Y) |
393 | continue; | 393 | continue; |
394 | if(minZ > triangle.pointA.Z && minZ > triangle.pointB.Z && minZ > triangle.pointC.Z) | 394 | if(minZ > triangle.pointA.Z && minZ > triangle.pointB.Z && minZ > triangle.pointC.Z) |
395 | continue; | 395 | continue; |
396 | if(maxZ < triangle.pointA.Z && maxZ < triangle.pointB.Z && maxZ < triangle.pointC.Z) | 396 | if(maxZ < triangle.pointA.Z && maxZ < triangle.pointB.Z && maxZ < triangle.pointC.Z) |
397 | continue; | 397 | continue; |
398 | 398 | ||
399 | if (triangle.getIntersectionWithLine(ray.start, linevect, intersection)) | 399 | if (triangle.getIntersectionWithLine(ray.start, linevect, intersection)) |
400 | { | 400 | { |
401 | const f32 tmp = intersection.getDistanceFromSQ(ray.start); | 401 | const f32 tmp = intersection.getDistanceFromSQ(ray.start); |
402 | const f32 tmp2 = intersection.getDistanceFromSQ(ray.end); | 402 | const f32 tmp2 = intersection.getDistanceFromSQ(ray.end); |
403 | 403 | ||
404 | if (tmp < raylength && tmp2 < raylength && tmp < nearest) | 404 | if (tmp < raylength && tmp2 < raylength && tmp < nearest) |
405 | { | 405 | { |
406 | nearest = tmp; | 406 | nearest = tmp; |
407 | outTriangle = triangle; | 407 | outTriangle = triangle; |
408 | outIntersection = intersection; | 408 | outIntersection = intersection; |
409 | outNode = selector->getSceneNodeForTriangle(i); | 409 | outNode = selector->getSceneNodeForTriangle(i); |
410 | found = true; | 410 | found = true; |
411 | } | 411 | } |
412 | } | 412 | } |
413 | } | 413 | } |
414 | 414 | ||
415 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | 415 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; |
416 | return found; | 416 | return found; |
417 | } | 417 | } |
418 | 418 | ||
419 | 419 | ||
420 | //! Collides a moving ellipsoid with a 3d world with gravity and returns | 420 | //! Collides a moving ellipsoid with a 3d world with gravity and returns |
421 | //! the resulting new position of the ellipsoid. | 421 | //! the resulting new position of the ellipsoid. |
422 | core::vector3df CSceneCollisionManager::getCollisionResultPosition( | 422 | core::vector3df CSceneCollisionManager::getCollisionResultPosition( |
423 | ITriangleSelector* selector, | 423 | ITriangleSelector* selector, |
424 | const core::vector3df &position, const core::vector3df& radius, | 424 | const core::vector3df &position, const core::vector3df& radius, |
425 | const core::vector3df& direction, | 425 | const core::vector3df& direction, |
426 | core::triangle3df& triout, | 426 | core::triangle3df& triout, |
427 | core::vector3df& hitPosition, | 427 | core::vector3df& hitPosition, |
428 | bool& outFalling, | 428 | bool& outFalling, |
429 | ISceneNode*& outNode, | 429 | ISceneNode*& outNode, |
430 | f32 slidingSpeed, | 430 | f32 slidingSpeed, |
431 | const core::vector3df& gravity) | 431 | const core::vector3df& gravity) |
432 | { | 432 | { |
433 | return collideEllipsoidWithWorld(selector, position, | 433 | return collideEllipsoidWithWorld(selector, position, |
434 | radius, direction, slidingSpeed, gravity, triout, hitPosition, outFalling, outNode); | 434 | radius, direction, slidingSpeed, gravity, triout, hitPosition, outFalling, outNode); |
435 | } | 435 | } |
436 | 436 | ||
437 | 437 | ||
438 | bool CSceneCollisionManager::testTriangleIntersection(SCollisionData* colData, | 438 | bool CSceneCollisionManager::testTriangleIntersection(SCollisionData* colData, |
439 | const core::triangle3df& triangle) | 439 | const core::triangle3df& triangle) |
440 | { | 440 | { |
441 | const core::plane3d<f32> trianglePlane = triangle.getPlane(); | 441 | const core::plane3d<f32> trianglePlane = triangle.getPlane(); |
442 | 442 | ||
443 | // only check front facing polygons | 443 | // only check front facing polygons |
444 | if ( !trianglePlane.isFrontFacing(colData->normalizedVelocity) ) | 444 | if ( !trianglePlane.isFrontFacing(colData->normalizedVelocity) ) |
445 | return false; | 445 | return false; |
446 | 446 | ||
447 | // get interval of plane intersection | 447 | // get interval of plane intersection |
448 | 448 | ||
449 | f32 t1, t0; | 449 | f32 t1, t0; |
450 | bool embeddedInPlane = false; | 450 | bool embeddedInPlane = false; |
451 | 451 | ||
452 | // calculate signed distance from sphere position to triangle plane | 452 | // calculate signed distance from sphere position to triangle plane |
453 | f32 signedDistToTrianglePlane = trianglePlane.getDistanceTo( | 453 | f32 signedDistToTrianglePlane = trianglePlane.getDistanceTo( |
454 | colData->basePoint); | 454 | colData->basePoint); |
455 | 455 | ||
456 | f32 normalDotVelocity = | 456 | f32 normalDotVelocity = |
457 | trianglePlane.Normal.dotProduct(colData->velocity); | 457 | trianglePlane.Normal.dotProduct(colData->velocity); |
458 | 458 | ||
459 | if ( core::iszero ( normalDotVelocity ) ) | 459 | if ( core::iszero ( normalDotVelocity ) ) |
460 | { | 460 | { |
461 | // sphere is traveling parallel to plane | 461 | // sphere is traveling parallel to plane |
462 | 462 | ||
463 | if (fabs(signedDistToTrianglePlane) >= 1.0f) | 463 | if (fabs(signedDistToTrianglePlane) >= 1.0f) |
464 | return false; // no collision possible | 464 | return false; // no collision possible |
465 | else | 465 | else |
466 | { | 466 | { |
467 | // sphere is embedded in plane | 467 | // sphere is embedded in plane |
468 | embeddedInPlane = true; | 468 | embeddedInPlane = true; |
469 | t0 = 0.0; | 469 | t0 = 0.0; |
470 | t1 = 1.0; | 470 | t1 = 1.0; |
471 | } | 471 | } |
472 | } | 472 | } |
473 | else | 473 | else |
474 | { | 474 | { |
475 | normalDotVelocity = core::reciprocal ( normalDotVelocity ); | 475 | normalDotVelocity = core::reciprocal ( normalDotVelocity ); |
476 | 476 | ||
477 | // N.D is not 0. Calculate intersection interval | 477 | // N.D is not 0. Calculate intersection interval |
478 | t0 = (-1.f - signedDistToTrianglePlane) * normalDotVelocity; | 478 | t0 = (-1.f - signedDistToTrianglePlane) * normalDotVelocity; |
479 | t1 = (1.f - signedDistToTrianglePlane) * normalDotVelocity; | 479 | t1 = (1.f - signedDistToTrianglePlane) * normalDotVelocity; |
480 | 480 | ||
481 | // Swap so t0 < t1 | 481 | // Swap so t0 < t1 |
482 | if (t0 > t1) { f32 tmp = t1; t1 = t0; t0 = tmp; } | 482 | if (t0 > t1) { f32 tmp = t1; t1 = t0; t0 = tmp; } |
483 | 483 | ||
484 | // check if at least one value is within the range | 484 | // check if at least one value is within the range |
485 | if (t0 > 1.0f || t1 < 0.0f) | 485 | if (t0 > 1.0f || t1 < 0.0f) |
486 | return false; // both t values are outside 1 and 0, no collision possible | 486 | return false; // both t values are outside 1 and 0, no collision possible |
487 | 487 | ||
488 | // clamp to 0 and 1 | 488 | // clamp to 0 and 1 |
489 | t0 = core::clamp ( t0, 0.f, 1.f ); | 489 | t0 = core::clamp ( t0, 0.f, 1.f ); |
490 | t1 = core::clamp ( t1, 0.f, 1.f ); | 490 | t1 = core::clamp ( t1, 0.f, 1.f ); |
491 | } | 491 | } |
492 | 492 | ||
493 | // at this point we have t0 and t1, if there is any intersection, it | 493 | // at this point we have t0 and t1, if there is any intersection, it |
494 | // is between this interval | 494 | // is between this interval |
495 | core::vector3df collisionPoint; | 495 | core::vector3df collisionPoint; |
496 | bool foundCollision = false; | 496 | bool foundCollision = false; |
497 | f32 t = 1.0f; | 497 | f32 t = 1.0f; |
498 | 498 | ||
499 | // first check the easy case: Collision within the triangle; | 499 | // first check the easy case: Collision within the triangle; |
500 | // if this happens, it must be at t0 and this is when the sphere | 500 | // if this happens, it must be at t0 and this is when the sphere |
501 | // rests on the front side of the triangle plane. This can only happen | 501 | // rests on the front side of the triangle plane. This can only happen |
502 | // if the sphere is not embedded in the triangle plane. | 502 | // if the sphere is not embedded in the triangle plane. |
503 | 503 | ||
504 | if (!embeddedInPlane) | 504 | if (!embeddedInPlane) |
505 | { | 505 | { |
506 | core::vector3df planeIntersectionPoint = | 506 | core::vector3df planeIntersectionPoint = |
507 | (colData->basePoint - trianglePlane.Normal) | 507 | (colData->basePoint - trianglePlane.Normal) |
508 | + (colData->velocity * t0); | 508 | + (colData->velocity * t0); |
509 | 509 | ||
510 | if (triangle.isPointInside(planeIntersectionPoint)) | 510 | if (triangle.isPointInside(planeIntersectionPoint)) |
511 | { | 511 | { |
512 | foundCollision = true; | 512 | foundCollision = true; |
513 | t = t0; | 513 | t = t0; |
514 | collisionPoint = planeIntersectionPoint; | 514 | collisionPoint = planeIntersectionPoint; |
515 | } | 515 | } |
516 | } | 516 | } |
517 | 517 | ||
518 | // if we havent found a collision already we will have to sweep | 518 | // if we havent found a collision already we will have to sweep |
519 | // the sphere against points and edges of the triangle. Note: A | 519 | // the sphere against points and edges of the triangle. Note: A |
520 | // collision inside the triangle will always happen before a | 520 | // collision inside the triangle will always happen before a |
521 | // vertex or edge collision. | 521 | // vertex or edge collision. |
522 | 522 | ||
523 | if (!foundCollision) | 523 | if (!foundCollision) |
524 | { | 524 | { |
525 | core::vector3df velocity = colData->velocity; | 525 | core::vector3df velocity = colData->velocity; |
526 | core::vector3df base = colData->basePoint; | 526 | core::vector3df base = colData->basePoint; |
527 | 527 | ||
528 | f32 velocitySqaredLength = velocity.getLengthSQ(); | 528 | f32 velocitySqaredLength = velocity.getLengthSQ(); |
529 | f32 a,b,c; | 529 | f32 a,b,c; |
530 | f32 newT; | 530 | f32 newT; |
531 | 531 | ||
532 | // for each edge or vertex a quadratic equation has to be solved: | 532 | // for each edge or vertex a quadratic equation has to be solved: |
533 | // a*t^2 + b*t + c = 0. We calculate a,b, and c for each test. | 533 | // a*t^2 + b*t + c = 0. We calculate a,b, and c for each test. |
534 | 534 | ||
535 | // check against points | 535 | // check against points |
536 | a = velocitySqaredLength; | 536 | a = velocitySqaredLength; |
537 | 537 | ||
538 | // p1 | 538 | // p1 |
539 | b = 2.0f * (velocity.dotProduct(base - triangle.pointA)); | 539 | b = 2.0f * (velocity.dotProduct(base - triangle.pointA)); |
540 | c = (triangle.pointA-base).getLengthSQ() - 1.f; | 540 | c = (triangle.pointA-base).getLengthSQ() - 1.f; |
541 | if (getLowestRoot(a,b,c,t, &newT)) | 541 | if (getLowestRoot(a,b,c,t, &newT)) |
542 | { | 542 | { |
543 | t = newT; | 543 | t = newT; |
544 | foundCollision = true; | 544 | foundCollision = true; |
545 | collisionPoint = triangle.pointA; | 545 | collisionPoint = triangle.pointA; |
546 | } | 546 | } |
547 | 547 | ||
548 | // p2 | 548 | // p2 |
549 | if (!foundCollision) | 549 | if (!foundCollision) |
550 | { | 550 | { |
551 | b = 2.0f * (velocity.dotProduct(base - triangle.pointB)); | 551 | b = 2.0f * (velocity.dotProduct(base - triangle.pointB)); |
552 | c = (triangle.pointB-base).getLengthSQ() - 1.f; | 552 | c = (triangle.pointB-base).getLengthSQ() - 1.f; |
553 | if (getLowestRoot(a,b,c,t, &newT)) | 553 | if (getLowestRoot(a,b,c,t, &newT)) |
554 | { | 554 | { |
555 | t = newT; | 555 | t = newT; |
556 | foundCollision = true; | 556 | foundCollision = true; |
557 | collisionPoint = triangle.pointB; | 557 | collisionPoint = triangle.pointB; |
558 | } | 558 | } |
559 | } | 559 | } |
560 | 560 | ||
561 | // p3 | 561 | // p3 |
562 | if (!foundCollision) | 562 | if (!foundCollision) |
563 | { | 563 | { |
564 | b = 2.0f * (velocity.dotProduct(base - triangle.pointC)); | 564 | b = 2.0f * (velocity.dotProduct(base - triangle.pointC)); |
565 | c = (triangle.pointC-base).getLengthSQ() - 1.f; | 565 | c = (triangle.pointC-base).getLengthSQ() - 1.f; |
566 | if (getLowestRoot(a,b,c,t, &newT)) | 566 | if (getLowestRoot(a,b,c,t, &newT)) |
567 | { | 567 | { |
568 | t = newT; | 568 | t = newT; |
569 | foundCollision = true; | 569 | foundCollision = true; |
570 | collisionPoint = triangle.pointC; | 570 | collisionPoint = triangle.pointC; |
571 | } | 571 | } |
572 | } | 572 | } |
573 | 573 | ||
574 | // check against edges: | 574 | // check against edges: |
575 | 575 | ||
576 | // p1 --- p2 | 576 | // p1 --- p2 |
577 | core::vector3df edge = triangle.pointB - triangle.pointA; | 577 | core::vector3df edge = triangle.pointB - triangle.pointA; |
578 | core::vector3df baseToVertex = triangle.pointA - base; | 578 | core::vector3df baseToVertex = triangle.pointA - base; |
579 | f32 edgeSqaredLength = edge.getLengthSQ(); | 579 | f32 edgeSqaredLength = edge.getLengthSQ(); |
580 | f32 edgeDotVelocity = edge.dotProduct(velocity); | 580 | f32 edgeDotVelocity = edge.dotProduct(velocity); |
581 | f32 edgeDotBaseToVertex = edge.dotProduct(baseToVertex); | 581 | f32 edgeDotBaseToVertex = edge.dotProduct(baseToVertex); |
582 | 582 | ||
583 | // calculate parameters for equation | 583 | // calculate parameters for equation |
584 | a = edgeSqaredLength* -velocitySqaredLength + | 584 | a = edgeSqaredLength* -velocitySqaredLength + |
585 | edgeDotVelocity*edgeDotVelocity; | 585 | edgeDotVelocity*edgeDotVelocity; |
586 | b = edgeSqaredLength* (2.f *velocity.dotProduct(baseToVertex)) - | 586 | b = edgeSqaredLength* (2.f *velocity.dotProduct(baseToVertex)) - |
587 | 2.0f*edgeDotVelocity*edgeDotBaseToVertex; | 587 | 2.0f*edgeDotVelocity*edgeDotBaseToVertex; |
588 | c = edgeSqaredLength* (1.f -baseToVertex.getLengthSQ()) + | 588 | c = edgeSqaredLength* (1.f -baseToVertex.getLengthSQ()) + |
589 | edgeDotBaseToVertex*edgeDotBaseToVertex; | 589 | edgeDotBaseToVertex*edgeDotBaseToVertex; |
590 | 590 | ||
591 | // does the swept sphere collide against infinite edge? | 591 | // does the swept sphere collide against infinite edge? |
592 | if (getLowestRoot(a,b,c,t,&newT)) | 592 | if (getLowestRoot(a,b,c,t,&newT)) |
593 | { | 593 | { |
594 | f32 f = (edgeDotVelocity*newT - edgeDotBaseToVertex) / edgeSqaredLength; | 594 | f32 f = (edgeDotVelocity*newT - edgeDotBaseToVertex) / edgeSqaredLength; |
595 | if (f >=0.0f && f <= 1.0f) | 595 | if (f >=0.0f && f <= 1.0f) |
596 | { | 596 | { |
597 | // intersection took place within segment | 597 | // intersection took place within segment |
598 | t = newT; | 598 | t = newT; |
599 | foundCollision = true; | 599 | foundCollision = true; |
600 | collisionPoint = triangle.pointA + (edge*f); | 600 | collisionPoint = triangle.pointA + (edge*f); |
601 | } | 601 | } |
602 | } | 602 | } |
603 | 603 | ||
604 | // p2 --- p3 | 604 | // p2 --- p3 |
605 | edge = triangle.pointC-triangle.pointB; | 605 | edge = triangle.pointC-triangle.pointB; |
606 | baseToVertex = triangle.pointB - base; | 606 | baseToVertex = triangle.pointB - base; |
607 | edgeSqaredLength = edge.getLengthSQ(); | 607 | edgeSqaredLength = edge.getLengthSQ(); |
608 | edgeDotVelocity = edge.dotProduct(velocity); | 608 | edgeDotVelocity = edge.dotProduct(velocity); |
609 | edgeDotBaseToVertex = edge.dotProduct(baseToVertex); | 609 | edgeDotBaseToVertex = edge.dotProduct(baseToVertex); |
610 | 610 | ||
611 | // calculate parameters for equation | 611 | // calculate parameters for equation |
612 | a = edgeSqaredLength* -velocitySqaredLength + | 612 | a = edgeSqaredLength* -velocitySqaredLength + |
613 | edgeDotVelocity*edgeDotVelocity; | 613 | edgeDotVelocity*edgeDotVelocity; |
614 | b = edgeSqaredLength* (2*velocity.dotProduct(baseToVertex)) - | 614 | b = edgeSqaredLength* (2*velocity.dotProduct(baseToVertex)) - |
615 | 2.0f*edgeDotVelocity*edgeDotBaseToVertex; | 615 | 2.0f*edgeDotVelocity*edgeDotBaseToVertex; |
616 | c = edgeSqaredLength* (1-baseToVertex.getLengthSQ()) + | 616 | c = edgeSqaredLength* (1-baseToVertex.getLengthSQ()) + |
617 | edgeDotBaseToVertex*edgeDotBaseToVertex; | 617 | edgeDotBaseToVertex*edgeDotBaseToVertex; |
618 | 618 | ||
619 | // does the swept sphere collide against infinite edge? | 619 | // does the swept sphere collide against infinite edge? |
620 | if (getLowestRoot(a,b,c,t,&newT)) | 620 | if (getLowestRoot(a,b,c,t,&newT)) |
621 | { | 621 | { |
622 | f32 f = (edgeDotVelocity*newT-edgeDotBaseToVertex) / | 622 | f32 f = (edgeDotVelocity*newT-edgeDotBaseToVertex) / |
623 | edgeSqaredLength; | 623 | edgeSqaredLength; |
624 | if (f >=0.0f && f <= 1.0f) | 624 | if (f >=0.0f && f <= 1.0f) |
625 | { | 625 | { |
626 | // intersection took place within segment | 626 | // intersection took place within segment |
627 | t = newT; | 627 | t = newT; |
628 | foundCollision = true; | 628 | foundCollision = true; |
629 | collisionPoint = triangle.pointB + (edge*f); | 629 | collisionPoint = triangle.pointB + (edge*f); |
630 | } | 630 | } |
631 | } | 631 | } |
632 | 632 | ||
633 | 633 | ||
634 | // p3 --- p1 | 634 | // p3 --- p1 |
635 | edge = triangle.pointA-triangle.pointC; | 635 | edge = triangle.pointA-triangle.pointC; |
636 | baseToVertex = triangle.pointC - base; | 636 | baseToVertex = triangle.pointC - base; |
637 | edgeSqaredLength = edge.getLengthSQ(); | 637 | edgeSqaredLength = edge.getLengthSQ(); |
638 | edgeDotVelocity = edge.dotProduct(velocity); | 638 | edgeDotVelocity = edge.dotProduct(velocity); |
639 | edgeDotBaseToVertex = edge.dotProduct(baseToVertex); | 639 | edgeDotBaseToVertex = edge.dotProduct(baseToVertex); |
640 | 640 | ||
641 | // calculate parameters for equation | 641 | // calculate parameters for equation |
642 | a = edgeSqaredLength* -velocitySqaredLength + | 642 | a = edgeSqaredLength* -velocitySqaredLength + |
643 | edgeDotVelocity*edgeDotVelocity; | 643 | edgeDotVelocity*edgeDotVelocity; |
644 | b = edgeSqaredLength* (2*velocity.dotProduct(baseToVertex)) - | 644 | b = edgeSqaredLength* (2*velocity.dotProduct(baseToVertex)) - |
645 | 2.0f*edgeDotVelocity*edgeDotBaseToVertex; | 645 | 2.0f*edgeDotVelocity*edgeDotBaseToVertex; |
646 | c = edgeSqaredLength* (1-baseToVertex.getLengthSQ()) + | 646 | c = edgeSqaredLength* (1-baseToVertex.getLengthSQ()) + |
647 | edgeDotBaseToVertex*edgeDotBaseToVertex; | 647 | edgeDotBaseToVertex*edgeDotBaseToVertex; |
648 | 648 | ||
649 | // does the swept sphere collide against infinite edge? | 649 | // does the swept sphere collide against infinite edge? |
650 | if (getLowestRoot(a,b,c,t,&newT)) | 650 | if (getLowestRoot(a,b,c,t,&newT)) |
651 | { | 651 | { |
652 | f32 f = (edgeDotVelocity*newT-edgeDotBaseToVertex) / | 652 | f32 f = (edgeDotVelocity*newT-edgeDotBaseToVertex) / |
653 | edgeSqaredLength; | 653 | edgeSqaredLength; |
654 | if (f >=0.0f && f <= 1.0f) | 654 | if (f >=0.0f && f <= 1.0f) |
655 | { | 655 | { |
656 | // intersection took place within segment | 656 | // intersection took place within segment |
657 | t = newT; | 657 | t = newT; |
658 | foundCollision = true; | 658 | foundCollision = true; |
659 | collisionPoint = triangle.pointC + (edge*f); | 659 | collisionPoint = triangle.pointC + (edge*f); |
660 | } | 660 | } |
661 | } | 661 | } |
662 | }// end no collision found | 662 | }// end no collision found |
663 | 663 | ||
664 | // set result: | 664 | // set result: |
665 | if (foundCollision) | 665 | if (foundCollision) |
666 | { | 666 | { |
667 | // distance to collision is t | 667 | // distance to collision is t |
668 | f32 distToCollision = t*colData->velocity.getLength(); | 668 | f32 distToCollision = t*colData->velocity.getLength(); |
669 | 669 | ||
670 | // does this triangle qualify for closest hit? | 670 | // does this triangle qualify for closest hit? |
671 | if (!colData->foundCollision || | 671 | if (!colData->foundCollision || |
672 | distToCollision < colData->nearestDistance) | 672 | distToCollision < colData->nearestDistance) |
673 | { | 673 | { |
674 | colData->nearestDistance = distToCollision; | 674 | colData->nearestDistance = distToCollision; |
675 | colData->intersectionPoint = collisionPoint; | 675 | colData->intersectionPoint = collisionPoint; |
676 | colData->foundCollision = true; | 676 | colData->foundCollision = true; |
677 | colData->intersectionTriangle = triangle; | 677 | colData->intersectionTriangle = triangle; |
678 | ++colData->triangleHits; | 678 | ++colData->triangleHits; |
679 | return true; | 679 | return true; |
680 | } | 680 | } |
681 | }// end found collision | 681 | }// end found collision |
682 | 682 | ||
683 | return false; | 683 | return false; |
684 | } | 684 | } |
685 | 685 | ||
686 | 686 | ||
687 | //! Collides a moving ellipsoid with a 3d world with gravity and returns | 687 | //! Collides a moving ellipsoid with a 3d world with gravity and returns |
688 | //! the resulting new position of the ellipsoid. | 688 | //! the resulting new position of the ellipsoid. |
689 | core::vector3df CSceneCollisionManager::collideEllipsoidWithWorld( | 689 | core::vector3df CSceneCollisionManager::collideEllipsoidWithWorld( |
690 | ITriangleSelector* selector, const core::vector3df &position, | 690 | ITriangleSelector* selector, const core::vector3df &position, |
691 | const core::vector3df& radius, const core::vector3df& velocity, | 691 | const core::vector3df& radius, const core::vector3df& velocity, |
692 | f32 slidingSpeed, | 692 | f32 slidingSpeed, |
693 | const core::vector3df& gravity, | 693 | const core::vector3df& gravity, |
694 | core::triangle3df& triout, | 694 | core::triangle3df& triout, |
695 | core::vector3df& hitPosition, | 695 | core::vector3df& hitPosition, |
696 | bool& outFalling, | 696 | bool& outFalling, |
697 | ISceneNode*& outNode) | 697 | ISceneNode*& outNode) |
698 | { | 698 | { |
699 | if (!selector || radius.X == 0.0f || radius.Y == 0.0f || radius.Z == 0.0f) | 699 | if (!selector || radius.X == 0.0f || radius.Y == 0.0f || radius.Z == 0.0f) |
700 | return position; | 700 | return position; |
701 | 701 | ||
702 | // This code is based on the paper "Improved Collision detection and Response" | 702 | // This code is based on the paper "Improved Collision detection and Response" |
703 | // by Kasper Fauerby, but some parts are modified. | 703 | // by Kasper Fauerby, but some parts are modified. |
704 | 704 | ||
705 | SCollisionData colData; | 705 | SCollisionData colData; |
706 | colData.R3Position = position; | 706 | colData.R3Position = position; |
707 | colData.R3Velocity = velocity; | 707 | colData.R3Velocity = velocity; |
708 | colData.eRadius = radius; | 708 | colData.eRadius = radius; |
709 | colData.nearestDistance = FLT_MAX; | 709 | colData.nearestDistance = FLT_MAX; |
710 | colData.selector = selector; | 710 | colData.selector = selector; |
711 | colData.slidingSpeed = slidingSpeed; | 711 | colData.slidingSpeed = slidingSpeed; |
712 | colData.triangleHits = 0; | 712 | colData.triangleHits = 0; |
713 | colData.triangleIndex = -1; | 713 | colData.triangleIndex = -1; |
714 | 714 | ||
715 | core::vector3df eSpacePosition = colData.R3Position / colData.eRadius; | 715 | core::vector3df eSpacePosition = colData.R3Position / colData.eRadius; |
716 | core::vector3df eSpaceVelocity = colData.R3Velocity / colData.eRadius; | 716 | core::vector3df eSpaceVelocity = colData.R3Velocity / colData.eRadius; |
717 | 717 | ||
718 | // iterate until we have our final position | 718 | // iterate until we have our final position |
719 | 719 | ||
720 | core::vector3df finalPos = collideWithWorld( | 720 | core::vector3df finalPos = collideWithWorld( |
721 | 0, colData, eSpacePosition, eSpaceVelocity); | 721 | 0, colData, eSpacePosition, eSpaceVelocity); |
722 | 722 | ||
723 | outFalling = false; | 723 | outFalling = false; |
724 | 724 | ||
725 | // add gravity | 725 | // add gravity |
726 | 726 | ||
727 | if (gravity != core::vector3df(0,0,0)) | 727 | if (gravity != core::vector3df(0,0,0)) |
728 | { | 728 | { |
729 | colData.R3Position = finalPos * colData.eRadius; | 729 | colData.R3Position = finalPos * colData.eRadius; |
730 | colData.R3Velocity = gravity; | 730 | colData.R3Velocity = gravity; |
731 | colData.triangleHits = 0; | 731 | colData.triangleHits = 0; |
732 | 732 | ||
733 | eSpaceVelocity = gravity/colData.eRadius; | 733 | eSpaceVelocity = gravity/colData.eRadius; |
734 | 734 | ||
735 | finalPos = collideWithWorld(0, colData, | 735 | finalPos = collideWithWorld(0, colData, |
736 | finalPos, eSpaceVelocity); | 736 | finalPos, eSpaceVelocity); |
737 | 737 | ||
738 | outFalling = (colData.triangleHits == 0); | 738 | outFalling = (colData.triangleHits == 0); |
739 | } | 739 | } |
740 | 740 | ||
741 | if (colData.triangleHits) | 741 | if (colData.triangleHits) |
742 | { | 742 | { |
743 | triout = colData.intersectionTriangle; | 743 | triout = colData.intersectionTriangle; |
744 | triout.pointA *= colData.eRadius; | 744 | triout.pointA *= colData.eRadius; |
745 | triout.pointB *= colData.eRadius; | 745 | triout.pointB *= colData.eRadius; |
746 | triout.pointC *= colData.eRadius; | 746 | triout.pointC *= colData.eRadius; |
747 | outNode = selector->getSceneNodeForTriangle(colData.triangleIndex); | 747 | outNode = selector->getSceneNodeForTriangle(colData.triangleIndex); |
748 | } | 748 | } |
749 | 749 | ||
750 | finalPos *= colData.eRadius; | 750 | finalPos *= colData.eRadius; |
751 | hitPosition = colData.intersectionPoint * colData.eRadius; | 751 | hitPosition = colData.intersectionPoint * colData.eRadius; |
752 | return finalPos; | 752 | return finalPos; |
753 | } | 753 | } |
754 | 754 | ||
755 | 755 | ||
756 | core::vector3df CSceneCollisionManager::collideWithWorld(s32 recursionDepth, | 756 | core::vector3df CSceneCollisionManager::collideWithWorld(s32 recursionDepth, |
757 | SCollisionData &colData, core::vector3df pos, core::vector3df vel) | 757 | SCollisionData &colData, core::vector3df pos, core::vector3df vel) |
758 | { | 758 | { |
759 | f32 veryCloseDistance = colData.slidingSpeed; | 759 | f32 veryCloseDistance = colData.slidingSpeed; |
760 | 760 | ||
761 | if (recursionDepth > 5) | 761 | if (recursionDepth > 5) |
762 | return pos; | 762 | return pos; |
763 | 763 | ||
764 | colData.velocity = vel; | 764 | colData.velocity = vel; |
765 | colData.normalizedVelocity = vel; | 765 | colData.normalizedVelocity = vel; |
766 | colData.normalizedVelocity.normalize(); | 766 | colData.normalizedVelocity.normalize(); |
767 | colData.basePoint = pos; | 767 | colData.basePoint = pos; |
768 | colData.foundCollision = false; | 768 | colData.foundCollision = false; |
769 | colData.nearestDistance = FLT_MAX; | 769 | colData.nearestDistance = FLT_MAX; |
770 | 770 | ||
771 | //------------------ collide with world | 771 | //------------------ collide with world |
772 | 772 | ||
773 | // get all triangles with which we might collide | 773 | // get all triangles with which we might collide |
774 | core::aabbox3d<f32> box(colData.R3Position); | 774 | core::aabbox3d<f32> box(colData.R3Position); |
775 | box.addInternalPoint(colData.R3Position + colData.R3Velocity); | 775 | box.addInternalPoint(colData.R3Position + colData.R3Velocity); |
776 | box.MinEdge -= colData.eRadius; | 776 | box.MinEdge -= colData.eRadius; |
777 | box.MaxEdge += colData.eRadius; | 777 | box.MaxEdge += colData.eRadius; |
778 | 778 | ||
779 | s32 totalTriangleCnt = colData.selector->getTriangleCount(); | 779 | s32 totalTriangleCnt = colData.selector->getTriangleCount(); |
780 | Triangles.set_used(totalTriangleCnt); | 780 | Triangles.set_used(totalTriangleCnt); |
781 | 781 | ||
782 | core::matrix4 scaleMatrix; | 782 | core::matrix4 scaleMatrix; |
783 | scaleMatrix.setScale( | 783 | scaleMatrix.setScale( |
784 | core::vector3df(1.0f / colData.eRadius.X, | 784 | core::vector3df(1.0f / colData.eRadius.X, |
785 | 1.0f / colData.eRadius.Y, | 785 | 1.0f / colData.eRadius.Y, |
786 | 1.0f / colData.eRadius.Z)); | 786 | 1.0f / colData.eRadius.Z)); |
787 | 787 | ||
788 | s32 triangleCnt = 0; | 788 | s32 triangleCnt = 0; |
789 | colData.selector->getTriangles(Triangles.pointer(), totalTriangleCnt, triangleCnt, box, &scaleMatrix); | 789 | colData.selector->getTriangles(Triangles.pointer(), totalTriangleCnt, triangleCnt, box, &scaleMatrix); |
790 | 790 | ||
791 | for (s32 i=0; i<triangleCnt; ++i) | 791 | for (s32 i=0; i<triangleCnt; ++i) |
792 | if(testTriangleIntersection(&colData, Triangles[i])) | 792 | if(testTriangleIntersection(&colData, Triangles[i])) |
793 | colData.triangleIndex = i; | 793 | colData.triangleIndex = i; |
794 | 794 | ||
795 | //---------------- end collide with world | 795 | //---------------- end collide with world |
796 | 796 | ||
797 | if (!colData.foundCollision) | 797 | if (!colData.foundCollision) |
798 | return pos + vel; | 798 | return pos + vel; |
799 | 799 | ||
800 | // original destination point | 800 | // original destination point |
801 | const core::vector3df destinationPoint = pos + vel; | 801 | const core::vector3df destinationPoint = pos + vel; |
802 | core::vector3df newBasePoint = pos; | 802 | core::vector3df newBasePoint = pos; |
803 | 803 | ||
804 | // only update if we are not already very close | 804 | // only update if we are not already very close |
805 | // and if so only move very close to intersection, not to the | 805 | // and if so only move very close to intersection, not to the |
806 | // exact point | 806 | // exact point |
807 | if (colData.nearestDistance >= veryCloseDistance) | 807 | if (colData.nearestDistance >= veryCloseDistance) |
808 | { | 808 | { |
809 | core::vector3df v = vel; | 809 | core::vector3df v = vel; |
810 | v.setLength( colData.nearestDistance - veryCloseDistance ); | 810 | v.setLength( colData.nearestDistance - veryCloseDistance ); |
811 | newBasePoint = colData.basePoint + v; | 811 | newBasePoint = colData.basePoint + v; |
812 | 812 | ||
813 | v.normalize(); | 813 | v.normalize(); |
814 | colData.intersectionPoint -= (v * veryCloseDistance); | 814 | colData.intersectionPoint -= (v * veryCloseDistance); |
815 | } | 815 | } |
816 | 816 | ||
817 | // calculate sliding plane | 817 | // calculate sliding plane |
818 | 818 | ||
819 | const core::vector3df slidePlaneOrigin = colData.intersectionPoint; | 819 | const core::vector3df slidePlaneOrigin = colData.intersectionPoint; |
820 | const core::vector3df slidePlaneNormal = (newBasePoint - colData.intersectionPoint).normalize(); | 820 | const core::vector3df slidePlaneNormal = (newBasePoint - colData.intersectionPoint).normalize(); |
821 | core::plane3d<f32> slidingPlane(slidePlaneOrigin, slidePlaneNormal); | 821 | core::plane3d<f32> slidingPlane(slidePlaneOrigin, slidePlaneNormal); |
822 | 822 | ||
823 | core::vector3df newDestinationPoint = | 823 | core::vector3df newDestinationPoint = |
824 | destinationPoint - | 824 | destinationPoint - |
825 | (slidePlaneNormal * slidingPlane.getDistanceTo(destinationPoint)); | 825 | (slidePlaneNormal * slidingPlane.getDistanceTo(destinationPoint)); |
826 | 826 | ||
827 | // generate slide vector | 827 | // generate slide vector |
828 | 828 | ||
829 | const core::vector3df newVelocityVector = newDestinationPoint - | 829 | const core::vector3df newVelocityVector = newDestinationPoint - |
830 | colData.intersectionPoint; | 830 | colData.intersectionPoint; |
831 | 831 | ||
832 | if (newVelocityVector.getLength() < veryCloseDistance) | 832 | if (newVelocityVector.getLength() < veryCloseDistance) |
833 | return newBasePoint; | 833 | return newBasePoint; |
834 | 834 | ||
835 | return collideWithWorld(recursionDepth+1, colData, | 835 | return collideWithWorld(recursionDepth+1, colData, |
836 | newBasePoint, newVelocityVector); | 836 | newBasePoint, newVelocityVector); |
837 | } | 837 | } |
838 | 838 | ||
839 | 839 | ||
840 | //! Returns a 3d ray which would go through the 2d screen coodinates. | 840 | //! Returns a 3d ray which would go through the 2d screen coodinates. |
841 | core::line3d<f32> CSceneCollisionManager::getRayFromScreenCoordinates( | 841 | core::line3d<f32> CSceneCollisionManager::getRayFromScreenCoordinates( |
842 | const core::position2d<s32> & pos, ICameraSceneNode* camera) | 842 | const core::position2d<s32> & pos, ICameraSceneNode* camera) |
843 | { | 843 | { |
844 | core::line3d<f32> ln(0,0,0,0,0,0); | 844 | core::line3d<f32> ln(0,0,0,0,0,0); |
845 | 845 | ||
846 | if (!SceneManager) | 846 | if (!SceneManager) |
847 | return ln; | 847 | return ln; |
848 | 848 | ||
849 | if (!camera) | 849 | if (!camera) |
850 | camera = SceneManager->getActiveCamera(); | 850 | camera = SceneManager->getActiveCamera(); |
851 | 851 | ||
852 | if (!camera) | 852 | if (!camera) |
853 | return ln; | 853 | return ln; |
854 | 854 | ||
855 | const scene::SViewFrustum* f = camera->getViewFrustum(); | 855 | const scene::SViewFrustum* f = camera->getViewFrustum(); |
856 | 856 | ||
857 | core::vector3df farLeftUp = f->getFarLeftUp(); | 857 | core::vector3df farLeftUp = f->getFarLeftUp(); |
858 | core::vector3df lefttoright = f->getFarRightUp() - farLeftUp; | 858 | core::vector3df lefttoright = f->getFarRightUp() - farLeftUp; |
859 | core::vector3df uptodown = f->getFarLeftDown() - farLeftUp; | 859 | core::vector3df uptodown = f->getFarLeftDown() - farLeftUp; |
860 | 860 | ||
861 | const core::rect<s32>& viewPort = Driver->getViewPort(); | 861 | const core::rect<s32>& viewPort = Driver->getViewPort(); |
862 | core::dimension2d<u32> screenSize(viewPort.getWidth(), viewPort.getHeight()); | 862 | core::dimension2d<u32> screenSize(viewPort.getWidth(), viewPort.getHeight()); |
863 | 863 | ||
864 | f32 dx = pos.X / (f32)screenSize.Width; | 864 | f32 dx = pos.X / (f32)screenSize.Width; |
865 | f32 dy = pos.Y / (f32)screenSize.Height; | 865 | f32 dy = pos.Y / (f32)screenSize.Height; |
866 | 866 | ||
867 | if (camera->isOrthogonal()) | 867 | if (camera->isOrthogonal()) |
868 | ln.start = f->cameraPosition + (lefttoright * (dx-0.5f)) + (uptodown * (dy-0.5f)); | 868 | ln.start = f->cameraPosition + (lefttoright * (dx-0.5f)) + (uptodown * (dy-0.5f)); |
869 | else | 869 | else |
870 | ln.start = f->cameraPosition; | 870 | ln.start = f->cameraPosition; |
871 | 871 | ||
872 | ln.end = farLeftUp + (lefttoright * dx) + (uptodown * dy); | 872 | ln.end = farLeftUp + (lefttoright * dx) + (uptodown * dy); |
873 | 873 | ||
874 | return ln; | 874 | return ln; |
875 | } | 875 | } |
876 | 876 | ||
877 | 877 | ||
878 | //! Calculates 2d screen position from a 3d position. | 878 | //! Calculates 2d screen position from a 3d position. |
879 | core::position2d<s32> CSceneCollisionManager::getScreenCoordinatesFrom3DPosition( | 879 | core::position2d<s32> CSceneCollisionManager::getScreenCoordinatesFrom3DPosition( |
880 | const core::vector3df & pos3d, ICameraSceneNode* camera, bool useViewPort) | 880 | const core::vector3df & pos3d, ICameraSceneNode* camera, bool useViewPort) |
881 | { | 881 | { |
882 | if (!SceneManager || !Driver) | 882 | if (!SceneManager || !Driver) |
883 | return core::position2d<s32>(-1000,-1000); | 883 | return core::position2d<s32>(-1000,-1000); |
884 | 884 | ||
885 | if (!camera) | 885 | if (!camera) |
886 | camera = SceneManager->getActiveCamera(); | 886 | camera = SceneManager->getActiveCamera(); |
887 | 887 | ||
888 | if (!camera) | 888 | if (!camera) |
889 | return core::position2d<s32>(-1000,-1000); | 889 | return core::position2d<s32>(-1000,-1000); |
890 | 890 | ||
891 | core::dimension2d<u32> dim; | 891 | core::dimension2d<u32> dim; |
892 | if (useViewPort) | 892 | if (useViewPort) |
893 | dim.set(Driver->getViewPort().getWidth(), Driver->getViewPort().getHeight()); | 893 | dim.set(Driver->getViewPort().getWidth(), Driver->getViewPort().getHeight()); |
894 | else | 894 | else |
895 | dim=(Driver->getCurrentRenderTargetSize()); | 895 | dim=(Driver->getCurrentRenderTargetSize()); |
896 | 896 | ||
897 | dim.Width /= 2; | 897 | dim.Width /= 2; |
898 | dim.Height /= 2; | 898 | dim.Height /= 2; |
899 | 899 | ||
900 | core::matrix4 trans = camera->getProjectionMatrix(); | 900 | core::matrix4 trans = camera->getProjectionMatrix(); |
901 | trans *= camera->getViewMatrix(); | 901 | trans *= camera->getViewMatrix(); |
902 | 902 | ||
903 | f32 transformedPos[4] = { pos3d.X, pos3d.Y, pos3d.Z, 1.0f }; | 903 | f32 transformedPos[4] = { pos3d.X, pos3d.Y, pos3d.Z, 1.0f }; |
904 | 904 | ||
905 | trans.multiplyWith1x4Matrix(transformedPos); | 905 | trans.multiplyWith1x4Matrix(transformedPos); |
906 | 906 | ||
907 | if (transformedPos[3] < 0) | 907 | if (transformedPos[3] < 0) |
908 | return core::position2d<s32>(-10000,-10000); | 908 | return core::position2d<s32>(-10000,-10000); |
909 | 909 | ||
910 | const f32 zDiv = transformedPos[3] == 0.0f ? 1.0f : | 910 | const f32 zDiv = transformedPos[3] == 0.0f ? 1.0f : |
911 | core::reciprocal(transformedPos[3]); | 911 | core::reciprocal(transformedPos[3]); |
912 | 912 | ||
913 | return core::position2d<s32>( | 913 | return core::position2d<s32>( |
914 | dim.Width + core::round32(dim.Width * (transformedPos[0] * zDiv)), | 914 | dim.Width + core::round32(dim.Width * (transformedPos[0] * zDiv)), |
915 | dim.Height - core::round32(dim.Height * (transformedPos[1] * zDiv))); | 915 | dim.Height - core::round32(dim.Height * (transformedPos[1] * zDiv))); |
916 | } | 916 | } |
917 | 917 | ||
918 | 918 | ||
919 | inline bool CSceneCollisionManager::getLowestRoot(f32 a, f32 b, f32 c, f32 maxR, f32* root) | 919 | inline bool CSceneCollisionManager::getLowestRoot(f32 a, f32 b, f32 c, f32 maxR, f32* root) |
920 | { | 920 | { |
921 | // check if solution exists | 921 | // check if solution exists |
922 | const f32 determinant = b*b - 4.0f*a*c; | 922 | const f32 determinant = b*b - 4.0f*a*c; |
923 | 923 | ||
924 | // if determinant is negative, no solution | 924 | // if determinant is negative, no solution |
925 | if (determinant < 0.0f || a == 0.f ) | 925 | if (determinant < 0.0f || a == 0.f ) |
926 | return false; | 926 | return false; |
927 | 927 | ||
928 | // calculate two roots: (if det==0 then x1==x2 | 928 | // calculate two roots: (if det==0 then x1==x2 |
929 | // but lets disregard that slight optimization) | 929 | // but lets disregard that slight optimization) |
930 | 930 | ||
931 | const f32 sqrtD = sqrtf(determinant); | 931 | const f32 sqrtD = sqrtf(determinant); |
932 | const f32 invDA = core::reciprocal(2*a); | 932 | const f32 invDA = core::reciprocal(2*a); |
933 | f32 r1 = (-b - sqrtD) * invDA; | 933 | f32 r1 = (-b - sqrtD) * invDA; |
934 | f32 r2 = (-b + sqrtD) * invDA; | 934 | f32 r2 = (-b + sqrtD) * invDA; |
935 | 935 | ||
936 | // sort so x1 <= x2 | 936 | // sort so x1 <= x2 |
937 | if (r1 > r2) | 937 | if (r1 > r2) |
938 | core::swap(r1,r2); | 938 | core::swap(r1,r2); |
939 | 939 | ||
940 | // get lowest root | 940 | // get lowest root |
941 | if (r1 > 0 && r1 < maxR) | 941 | if (r1 > 0 && r1 < maxR) |
942 | { | 942 | { |
943 | *root = r1; | 943 | *root = r1; |
944 | return true; | 944 | return true; |
945 | } | 945 | } |
946 | 946 | ||
947 | // its possible that we want x2, this can happen if x1 < 0 | 947 | // its possible that we want x2, this can happen if x1 < 0 |
948 | if (r2 > 0 && r2 < maxR) | 948 | if (r2 > 0 && r2 < maxR) |
949 | { | 949 | { |
950 | *root = r2; | 950 | *root = r2; |
951 | return true; | 951 | return true; |
952 | } | 952 | } |
953 | 953 | ||
954 | return false; | 954 | return false; |
955 | } | 955 | } |
956 | 956 | ||
957 | 957 | ||
958 | } // end namespace scene | 958 | } // end namespace scene |
959 | } // end namespace irr | 959 | } // end namespace irr |
960 | 960 | ||