Commit 2dc5c7d7 authored by cutealien's avatar cutealien

- Reversed change in vector3d::normalize. The check for 0 vector isn't there...

- Reversed change in vector3d::normalize. The check for 0 vector isn't there for optimization, but to prevent NAN values.
  Works now again as documented and a corresponding test has been added.
  Does fix bug 2770709 (https://sourceforge.net/tracker/?func=detail&aid=2770709&group_id=74339&atid=540676)
- Animations can now be paused by setting the fps to 0.
- Avoid fp-precision problem in getPickedNodeBB (see also 
http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=33838&highlight=). 
  This change might also fix the problem with picking nodes found by aanderse 
(http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=32890&highlight=)



git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@2419 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 2391338b
...@@ -13,7 +13,7 @@ namespace core ...@@ -13,7 +13,7 @@ namespace core
{ {
//! 3d vector template class with lots of operators and methods. //! 3d vector template class with lots of operators and methods.
/** The vector3d class is used in Irrlicht for three main purposes: /** The vector3d class is used in Irrlicht for three main purposes:
1) As a direction vector (most of the methods assume this). 1) As a direction vector (most of the methods assume this).
2) As a position in 3d space (which is synonymous with a direction vector from the origin to this position). 2) As a position in 3d space (which is synonymous with a direction vector from the origin to this position).
3) To hold three Euler rotations, where X is pitch, Y is yaw and Z is roll. 3) To hold three Euler rotations, where X is pitch, Y is yaw and Z is roll.
...@@ -140,8 +140,11 @@ namespace core ...@@ -140,8 +140,11 @@ namespace core
\return Reference to this vector after normalization. */ \return Reference to this vector after normalization. */
vector3d<T>& normalize() vector3d<T>& normalize()
{ {
const f64 length = core::reciprocal_squareroot ( (f64) (X*X + Y*Y + Z*Z) ); f64 length = (f32)(X*X + Y*Y + Z*Z);
if (core::equals(length, 0.0)) // this check isn't an optimization but prevents getting NAN in the sqrt.
return *this;
length = core::reciprocal_squareroot ( (f64) (X*X + Y*Y + Z*Z) );
X = (T)(X * length); X = (T)(X * length);
Y = (T)(Y * length); Y = (T)(Y * length);
Z = (T)(Z * length); Z = (T)(Z * length);
...@@ -263,10 +266,10 @@ namespace core ...@@ -263,10 +266,10 @@ namespace core
// Where target and seeker are of type ISceneNode* // Where target and seeker are of type ISceneNode*
const vector3df toTarget(target->getAbsolutePosition() - seeker->getAbsolutePosition()); const vector3df toTarget(target->getAbsolutePosition() - seeker->getAbsolutePosition());
const vector3df requiredRotation = toTarget.getHorizontalAngle(); const vector3df requiredRotation = toTarget.getHorizontalAngle();
seeker->setRotation(requiredRotation); seeker->setRotation(requiredRotation);
\return A rotation vector containing the X (pitch) and Y (raw) rotations (in degrees) that when applied to a \return A rotation vector containing the X (pitch) and Y (raw) rotations (in degrees) that when applied to a
+Z (e.g. 0, 0, 1) direction vector would make it point in the same direction as this vector. The Z (roll) rotation +Z (e.g. 0, 0, 1) direction vector would make it point in the same direction as this vector. The Z (roll) rotation
is always 0, since two Euler rotations are sufficient to point in any given direction. */ is always 0, since two Euler rotations are sufficient to point in any given direction. */
vector3d<T> getHorizontalAngle() const vector3d<T> getHorizontalAngle() const
{ {
...@@ -295,9 +298,9 @@ namespace core ...@@ -295,9 +298,9 @@ namespace core
/** This vector is assumed to be a rotation vector composed of 3 Euler angle rotations, in degrees. /** This vector is assumed to be a rotation vector composed of 3 Euler angle rotations, in degrees.
The implementation performs the same calculations as using a matrix to do the rotation. The implementation performs the same calculations as using a matrix to do the rotation.
\param[in] forwards The direction representing "forwards" which will be rotated by this vector. \param[in] forwards The direction representing "forwards" which will be rotated by this vector.
If you do not provide a direction, then the +Z axis (0, 0, 1) will be assumed to be forwards. If you do not provide a direction, then the +Z axis (0, 0, 1) will be assumed to be forwards.
\return A direction vector calculated by rotating the forwards direction by the 3 Euler angles \return A direction vector calculated by rotating the forwards direction by the 3 Euler angles
(in degrees) represented by this vector. */ (in degrees) represented by this vector. */
vector3d<T> rotationToDirection(const vector3d<T> & forwards = vector3d<T>(0, 0, 1)) const vector3d<T> rotationToDirection(const vector3d<T> & forwards = vector3d<T>(0, 0, 1)) const
{ {
......
...@@ -107,7 +107,7 @@ void CAnimatedMeshSceneNode::buildFrameNr(u32 timeMs) ...@@ -107,7 +107,7 @@ void CAnimatedMeshSceneNode::buildFrameNr(u32 timeMs)
} }
} }
if ((StartFrame==EndFrame) || (FramesPerSecond==0.f)) if ((StartFrame==EndFrame))
{ {
CurrentFrameNr = (f32)StartFrame; //Support for non animated meshes CurrentFrameNr = (f32)StartFrame; //Support for non animated meshes
} }
...@@ -210,7 +210,7 @@ IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame(bool forceRecalcOfControl ...@@ -210,7 +210,7 @@ IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame(bool forceRecalcOfControl
if (JointMode == EJUOR_CONTROL)//write to mesh if (JointMode == EJUOR_CONTROL)//write to mesh
skinnedMesh->transferJointsToMesh(JointChildSceneNodes); skinnedMesh->transferJointsToMesh(JointChildSceneNodes);
else else
skinnedMesh->animateMesh(getFrameNr(), 1.0f); skinnedMesh->animateMesh(getFrameNr(), 1.0f);
// Update the skinned mesh for the current joint transforms. // Update the skinned mesh for the current joint transforms.
...@@ -242,12 +242,12 @@ IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame(bool forceRecalcOfControl ...@@ -242,12 +242,12 @@ IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame(bool forceRecalcOfControl
//! OnAnimate() is called just before rendering the whole scene. //! OnAnimate() is called just before rendering the whole scene.
void CAnimatedMeshSceneNode::OnAnimate(u32 timeMs) void CAnimatedMeshSceneNode::OnAnimate(u32 timeMs)
{ {
buildFrameNr(timeMs-LastTimeMs); buildFrameNr(timeMs-LastTimeMs);
if ( Mesh ) if ( Mesh )
{ {
scene::IMesh * mesh = getMeshForCurrentFrame( true ); scene::IMesh * mesh = getMeshForCurrentFrame( true );
if ( mesh ) if ( mesh )
Box = mesh->getBoundingBox(); Box = mesh->getBoundingBox();
} }
...@@ -886,7 +886,7 @@ void CAnimatedMeshSceneNode::updateAbsolutePosition() ...@@ -886,7 +886,7 @@ void CAnimatedMeshSceneNode::updateAbsolutePosition()
SMD3QuaternionTag parent ( MD3Special->Tagname ); SMD3QuaternionTag parent ( MD3Special->Tagname );
if ( Parent && Parent->getType () == ESNT_ANIMATED_MESH) if ( Parent && Parent->getType () == ESNT_ANIMATED_MESH)
{ {
const SMD3QuaternionTag * p = ((IAnimatedMeshSceneNode*) Parent)->getMD3TagTransformation const SMD3QuaternionTag * p = ((IAnimatedMeshSceneNode*) Parent)->getMD3TagTransformation
( MD3Special->Tagname ); ( MD3Special->Tagname );
if ( p ) if ( p )
......
...@@ -149,9 +149,10 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root, core::line3df& ra ...@@ -149,9 +149,10 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root, core::line3df& ra
core::vector3df intersection; core::vector3df intersection;
core::plane3df facePlane; core::plane3df facePlane;
f32 bestDistToBoxBorder = FLT_MAX;
f32 bestToIntersectionSq = FLT_MAX;
bool gotHit = false; for(s32 face = 0; face < 6; ++face)
for(s32 face = 0; face < 6 && !gotHit; ++face)
{ {
facePlane.setPlane(edges[faceEdges[face][0]], facePlane.setPlane(edges[faceEdges[face][0]],
edges[faceEdges[face][1]], edges[faceEdges[face][1]],
...@@ -170,21 +171,18 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root, core::line3df& ra ...@@ -170,21 +171,18 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root, core::line3df& ra
if(toIntersectionSq < outbestdistance) if(toIntersectionSq < outbestdistance)
{ {
// We have to check that the intersection with this plane is actually // We have to check that the intersection with this plane is actually
// on the box, so need to go back to object space again. We also // on the box, so need to go back to object space again.
// need to move the intersection very slightly closer to the centre of
// the box to take into account fp precision losses, since the intersection
// will axiomatically be on the very edge of the box.
worldToObject.transformVect(intersection); worldToObject.transformVect(intersection);
intersection *= 0.99f;
if(objectBox.isPointInside(intersection)) // find the closes point on the box borders. Have to do this as exact checks will fail due to floating point problems.
{ f32 distToBorder = core::max_ ( core::min_ (core::abs_(objectBox.MinEdge.X-intersection.X), core::abs_(objectBox.MaxEdge.X-intersection.X)),
outbestdistance = toIntersectionSq; core::min_ (core::abs_(objectBox.MinEdge.Y-intersection.Y), core::abs_(objectBox.MaxEdge.Y-intersection.Y)),
outbestnode = current; core::min_ (core::abs_(objectBox.MinEdge.Z-intersection.Z), core::abs_(objectBox.MaxEdge.Z-intersection.Z)) );
if ( distToBorder < bestDistToBoxBorder )
// We can only hit one face, so stop checking now. {
gotHit = true; bestDistToBoxBorder = distToBorder;
} bestToIntersectionSq = toIntersectionSq;
}
} }
} }
...@@ -194,9 +192,14 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root, core::line3df& ra ...@@ -194,9 +192,14 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root, core::line3df& ra
++face; ++face;
} }
// If we got a hit, we can now truncate the ray to stop us hitting further nodes. if ( bestDistToBoxBorder < FLT_MAX )
if (gotHit) {
ray.end = ray.start + (rayVector * sqrtf(outbestdistance)); outbestdistance = bestToIntersectionSq;
outbestnode = current;
// If we got a hit, we can now truncate the ray to stop us hitting further nodes.
ray.end = ray.start + (rayVector * sqrtf(outbestdistance));
}
} }
} }
......
...@@ -8,13 +8,22 @@ ...@@ -8,13 +8,22 @@
using namespace irr; using namespace irr;
using namespace core; using namespace core;
// check if the vector contains a NAN (a==b is guaranteed to return false in this case)
template<class T>
static bool is_nan(const core::vector3d<T> &vec )
{
return ( !(vec.X == vec.X)
|| !(vec.Y == vec.Y)
|| !(vec.Z == vec.Z) );
}
template<class T> template<class T>
static bool compareVectors(const core::vector3d<T> & compare, static bool compareVectors(const core::vector3d<T> & compare,
const core::vector3d<T> & with) const core::vector3d<T> & with)
{ {
if(compare != with) if(compare != with)
{ {
logTestString("\nERROR: vector3d %.16f, %.16f, %.16f != vector3d %.16f, %.16f, %.16f\n", logTestString("\nERROR: vector3dOr %.16f, %.16f, %.16f != vector3d %.16f, %.16f, %.16f\n",
(f64)compare.X, (f64)compare.Y, (f64)compare.Z, (f64)compare.X, (f64)compare.Y, (f64)compare.Z,
(f64)with.X, (f64)with.Y, (f64)with.Z); (f64)with.X, (f64)with.Y, (f64)with.Z);
assert(compare == with); assert(compare == with);
...@@ -113,6 +122,11 @@ static bool doTests() ...@@ -113,6 +122,11 @@ static bool doTests()
interpolated = vec.getInterpolated_quadratic(otherVec, thirdVec, 1.f); interpolated = vec.getInterpolated_quadratic(otherVec, thirdVec, 1.f);
COMPARE_VECTORS(interpolated, thirdVec); // 1.f means all the 3rd vector COMPARE_VECTORS(interpolated, thirdVec); // 1.f means all the 3rd vector
vec.set(0,0,0);
vec.setLength(99);
if ( is_nan(vec) )
return false;
return true; return true;
} }
......
Test suite pass at GMT Wed Jun 10 20:04:22 2009 Test suite pass at GMT Thu Jun 11 22:44:22 2009
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment