ok I had the same thoughts. I tried serveral ways, but without success. I'm searching this error for 3 days, maybe I'm overseeing something. First I did as you told, but I hasn't worked, then I renamed the class raycast to TreeRayCast and added a new Class HeightFieldRayCast.
Here my code so far:
OgreNewt_CollisionPrimitives.h:
//! HeightField Collision
/*!
Builds a HeightField collision from raw data or directly from a OgreTerrain page
more info: http://newtondynamics.com/wiki/index.php5?title=NewtonCreateHeightFieldCollision
*/
class _OgreNewtExport HeightField : public Collision
{
public:
HeightField(const World* world): Collision(world){}
HeightField(const World* world, int width, int height, int gridsDiagonals, unsigned short *elevationMap, char *attributeMap, Ogre::Real horizontalScale, Ogre::Real verticleScale, int shapeID);
HeightField(const World* world, Ogre::Terrain *terrain, int shapeID);
~HeightField(){}
void setRayCastCallbackactive(bool active = true)
{
setRayCastCallbackactive( active, m_col );
}
//! used internally
static float _CDECL newtonRayCastCallback(float distance, float* normal, int faceId, void* userData);
private:
static void setRayCastCallbackactive( bool active , const NewtonCollision *col );
//!Used internally to create the newton Heightfield collision
//void createHeightFieldCollision(const World *world,int width,int height,int gridsDiagonals,unsigned short *elevationMap,char *attributeMap,Ogre::Real horizontalScale,Ogre::Real verticleScale,int shapeID);
};
OgreNewt_CollisionPrimitives.cpp:
HeightField::HeightField(const OgreNewt::World *world, Ogre::Terrain *terrain, int shapeID)
: Collision (world)
{
int width = terrain->getSize();
int height = width;
int gridsDiagonals = 0;
char *attributes;
unsigned short *elevations;
float *hData = terrain->getHeightData();
float verticleScale = 65535 / (terrain->getMaxHeight() - terrain->getMinHeight());
Ogre::Real horizontalScale = terrain->getWorldSize() / (terrain->getSize() - 1);
elevations = (unsigned short*) malloc (width * height * sizeof (unsigned short));
attributes = (char*) malloc (width * height * sizeof (char));
memset (attributes, 1, width * height * sizeof (char));
//HeightData reversed and mirror on X axis
int x = 0;
for (int i = width * height - 1; i >= 0; i--)
{
elevations[i-width+(x*2)+1] = unsigned short(*(hData)*verticleScale);
hData++;
x++;
if (x == width) x = 0;
}
//createHeightFieldCollision(world, width, height, gridsDiagonals, elevations, attributes, horizontalScale, float(1 / verticleScale), shapeID);
m_col = NewtonCreateHeightFieldCollision(world->getNewtonWorld(), width, height, gridsDiagonals, elevations, attributes, float(horizontalScale), float(1.0f / verticleScale), shapeID);
free (elevations);
free (attributes);
//NewtonReleaseCollision(world->getNewtonWorld(), m_col);
}
HeightField::HeightField(const OgreNewt::World *world, int width, int height, int gridsDiagonals, unsigned short *elevationMap, char *attributeMap, Ogre::Real horizontalScale, Ogre::Real verticleScale, int shapeID)
: Collision (world)
{
m_col = NewtonCreateHeightFieldCollision(world->getNewtonWorld(),width,height,gridsDiagonals,elevationMap,attributeMap,float(horizontalScale),float(verticleScale),shapeID);
}
float _CDECL HeightField::newtonRayCastCallback(float interception, float *normal, int faceId, void *userData)
{
Body* bod = ((HeightFieldRaycast*)userData)->m_heightfieldcollisioncallback_lastbody;
//! TODO: what do we need to return here?
if(!bod)
return 0;
((HeightFieldRaycast*)userData)->userCallback( bod, interception, Ogre::Vector3(normal[0], normal[1], normal[2]), faceId );
((HeightFieldRaycast*)userData)->m_heightfieldcollisioncallback_bodyalreadyadded = true;
return interception;
}
void HeightField::setRayCastCallbackactive(bool active, const NewtonCollision *col )
{
if(active)
NewtonTreeCollisionSetUserRayCastCallback( col, newtonRayCastCallback );
else
NewtonTreeCollisionSetUserRayCastCallback( col, NULL );
}
OgreNewt_RayCast.h:
/*
OgreNewt Library
Ogre implementation of Newton Game Dynamics SDK
OgreNewt basically has no license, you may use any or all of the library however you desire... I hope it can help you in any way.
by Walaber
some changes by melven
*/
#ifndef _INCLUDE_OGRENEWT_RAYCAST
#define _INCLUDE_OGRENEWT_RAYCAST
#include "OgreNewt_Prerequisites.h"
#include "OgreNewt_CollisionPrimitives.h"
// OgreNewt namespace. all functions and classes use this namespace.
namespace OgreNewt
{
//! general raycast
/*!
General class representing a raycast query in the Newton world. this class should be inherited to create specific raycast behavior.
*/
class _OgreNewtExport TreeRaycast
{
public:
//! constructor
TreeRaycast();
//! destuctor.
virtual ~TreeRaycast();
//! performs the raycast.
/*!
call after creating the object.
\param world pointer to the OgreNewt::World
\param startpt starting point of ray in global space
\param endpt ending point of ray in global space
*/
void go( const OgreNewt::World* world, const Ogre::Vector3& startpt, const Ogre::Vector3& endpt );
//! user callback pre-filter function.
/*!
This function is an optional pre-filter to completely ignore specific bodies during the raycast.
return false from this function to ignore this body, return true (default) to accept it.
*/
virtual bool userPreFilterCallback( OgreNewt::Body* body ) { return true; }
//! user callback filter function
/*! user callback function.
This function must be implemented by the user.
Newton calls this function for each body intersected by the ray. however it doesn't
necessarily go perfect cloest-to-farthest order.
return true and the callback will only be called for bodies closer to the start point than the current body.
return false and the callback will call for any other bodies, even those farther than the current one.
*/
virtual bool userCallback( OgreNewt::Body* body, Ogre::Real distance, const Ogre::Vector3& normal, int collisionID ) = 0;
friend float CollisionPrimitives::TreeCollision::newtonRayCastCallback(float distance, float *normal, int faceId, void *userData);
protected:
//! save the last OgreNewt::Body from the newtonRaycastPreFilter to use this for example the TreeCollisionRayCallback
OgreNewt::Body *m_treecollisioncallback_lastbody;
//! save if this body was already added by RayCastCallback from TreeCollision
bool m_treecollisioncallback_bodyalreadyadded;
private:
//! callback used for running the raycast itself... used internally
static float _CDECL newtonRaycastFilter(const NewtonBody* body, const float* hitNormal, int collisionID, void* userData, float intersetParam);
//! callback used for running the raycast prefilder... used internally
static unsigned _CDECL newtonRaycastPreFilter( const NewtonBody* body, const NewtonCollision* collision, void* userData );
};
//! general raycast
/*!
General class representing a raycast query in the Newton world. this class should be inherited to create specific raycast behavior.
*/
class _OgreNewtExport HeightFieldRaycast
{
public:
//! constructor
HeightFieldRaycast();
//! destuctor.
virtual ~HeightFieldRaycast();
//! performs the raycast.
/*!
call after creating the object.
\param world pointer to the OgreNewt::World
\param startpt starting point of ray in global space
\param endpt ending point of ray in global space
*/
void go( const OgreNewt::World* world, const Ogre::Vector3& startpt, const Ogre::Vector3& endpt );
//! user callback pre-filter function.
/*!
This function is an optional pre-filter to completely ignore specific bodies during the raycast.
return false from this function to ignore this body, return true (default) to accept it.
*/
virtual bool userPreFilterCallback( OgreNewt::Body* body ) { return true; }
//! user callback filter function
/*! user callback function.
This function must be implemented by the user.
Newton calls this function for each body intersected by the ray. however it doesn't
necessarily go perfect cloest-to-farthest order.
return true and the callback will only be called for bodies closer to the start point than the current body.
return false and the callback will call for any other bodies, even those farther than the current one.
*/
virtual bool userCallback( OgreNewt::Body* body, Ogre::Real distance, const Ogre::Vector3& normal, int collisionID ) = 0;
friend float CollisionPrimitives::HeightField::newtonRayCastCallback(float distance, float *normal, int faceId, void *userData);
protected:
//! save the last OgreNewt::Body from the newtonRaycastPreFilter to use this for example the HeightFieldRayCallback
OgreNewt::Body *m_heightfieldcollisioncallback_lastbody;
//! save if this body was already added by RayCastCallback from HeightFieldCollision
bool m_heightfieldcollisioncallback_bodyalreadyadded;
private:
//! callback used for running the raycast itself... used internally
static float _CDECL newtonRaycastFilter(const NewtonBody* body, const float* hitNormal, int collisionID, void* userData, float intersetParam);
//! callback used for running the raycast prefilder... used internally
static unsigned _CDECL newtonRaycastPreFilter( const NewtonBody* body, const NewtonCollision* collision, void* userData );
};
//! Basic implementation of the raycast
/*!
This class is provided for general raycast use. it returns information about all bodies hit by the ray.
*/
class _OgreNewtExport BasicRaycast : public TreeRaycast, HeightFieldRaycast
{
public:
//! simple class that represents a single raycast rigid body intersection.
class _OgreNewtExport BasicRaycastInfo
{
public:
BasicRaycastInfo();
~BasicRaycastInfo();
Ogre::Real getDistance() { return mDistance; };
OgreNewt::Body* getBody() { return mBody; };
int getCollisionId() { return mCollisionID; };
Ogre::Vector3 getNormal() { return mNormal; };
Ogre::Quaternion getNormalOrientation() { return OgreNewt::Converters::grammSchmidt(mNormal); };
Ogre::Real mDistance; //!< dist from point1 of the raycast, in range [0,1].
OgreNewt::Body* mBody; //!< pointer to body intersected with
int mCollisionID; //!< collision ID of the primitive hit by the ray (for compound collision bodies)
Ogre::Vector3 mNormal; //!< normal of intersection.
bool operator<(const BasicRaycastInfo& rhs) const
{
return mDistance < rhs.mDistance;
}
};
//! empty constructor
BasicRaycast();
//! constructor
/*!
performs a raycast, then the results can be queried from the object after creation.
\param world pointer to the OgreNewt::World
\param startpt starting point of the ray in global space
\param endpt ending point of the ray in global space
\param sorted sort the results by distance
*/
BasicRaycast( const OgreNewt::World* world, const Ogre::Vector3& startpt, const Ogre::Vector3& endpt, bool sorted);
//! perform a raycast
/*!
performs a raycast, then the results can be queried from the object after creation.
\param world pointer to the OgreNewt::World
\param startpt starting point of the ray in global space
\param endpt ending point of the ray in global space
\param sorted sort the results by distance
*/
void go( const OgreNewt::World* world, const Ogre::Vector3& startpt, const Ogre::Vector3& endpt, bool sorted);
//! destuctor.
~BasicRaycast();
//! the all-important custom callback function.
bool userCallback( Body* body, Ogre::Real distance, const Ogre::Vector3& normal, int collisionID );
// ------------------------------------------------------
// the following functions can be used to retrieve information about the bodies collided by the ray.
//! how many bodies did we hit?
int getHitCount() const;
//! retrieve the raycast info for a specific hit.
BasicRaycastInfo getInfoAt( unsigned int hitnum ) const;
//! get the closest body hit by the ray.
BasicRaycastInfo getFirstHit() const;
private:
// container for results.
typedef std::vector<BasicRaycastInfo> RaycastInfoList;
RaycastInfoList mRayList;
};
} // end NAMESPACE OgreNewt
#endif // _INCLUDE_OGRENEWT_RAYCAST
OgreNewt_RayCast.cpp:
#include "OgreNewt_stdafx.h"
#include "OgreNewt_Body.h"
#include "OgreNewt_World.h"
#include "OgreNewt_RayCast.h"
#include "OgreNewt_Tools.h"
#include "OgreNewt_Debugger.h"
#include "OgreNewt_Collision.h"
namespace OgreNewt
{
TreeRaycast::TreeRaycast() {}
TreeRaycast::~TreeRaycast() {}
void TreeRaycast::go(const OgreNewt::World* world, const Ogre::Vector3& startpt, const Ogre::Vector3& endpt )
{
if( world->getDebugger().isRaycastRecording() )
{
world->getDebugger().addRay(startpt, endpt);
}
m_treecollisioncallback_lastbody = NULL;
// perform the raycast!
NewtonWorldRayCast( world->getNewtonWorld(), (float*)&startpt, (float*)&endpt, OgreNewt::TreeRaycast::newtonRaycastFilter, this, OgreNewt::TreeRaycast::newtonRaycastPreFilter );
m_treecollisioncallback_lastbody = NULL;
}
float _CDECL TreeRaycast::newtonRaycastFilter(const NewtonBody* body, const float* hitNormal, int collisionID, void* userData, float intersectParam)
{
// get our object!
TreeRaycast* me = (TreeRaycast*)userData;
Body* bod = (Body*)NewtonBodyGetUserData( body );
const World* world = bod->getWorld();
Ogre::Vector3 normal = Ogre::Vector3( hitNormal[0], hitNormal[1], hitNormal[2] );
if( me->m_treecollisioncallback_bodyalreadyadded)
return intersectParam;
if( world->getDebugger().isRaycastRecording() && world->getDebugger().isRaycastRecordingHitBodies() )
{
world->getDebugger().addHitBody(bod);
}
if (me->userCallback( bod, intersectParam, normal, collisionID ))
return intersectParam;
else
return 1.1f;
}
unsigned _CDECL TreeRaycast::newtonRaycastPreFilter(const NewtonBody *body, const NewtonCollision *collision, void* userData)
{
// get our object!
TreeRaycast* me = (TreeRaycast*)userData;
Body* bod = (Body*)NewtonBodyGetUserData( body );
const World* world = bod->getWorld();
me->m_treecollisioncallback_bodyalreadyadded = false;
me->m_treecollisioncallback_lastbody = bod;
if (me->userPreFilterCallback( bod ))
return 1;
else
{
if( world->getDebugger().isRaycastRecording() && world->getDebugger().isRaycastRecordingHitBodies() )
{
world->getDebugger().addDiscardedBody(bod);
}
return 0;
}
}
//--------------------------------
HeightFieldRaycast::HeightFieldRaycast() {}
HeightFieldRaycast::~HeightFieldRaycast() {}
void HeightFieldRaycast::go(const OgreNewt::World* world, const Ogre::Vector3& startpt, const Ogre::Vector3& endpt )
{
if( world->getDebugger().isRaycastRecording() )
{
world->getDebugger().addRay(startpt, endpt);
}
m_heightfieldcollisioncallback_lastbody = NULL;
// perform the raycast!
NewtonWorldRayCast( world->getNewtonWorld(), (float*)&startpt, (float*)&endpt, OgreNewt::HeightFieldRaycast::newtonRaycastFilter, this, OgreNewt::HeightFieldRaycast::newtonRaycastPreFilter );
m_heightfieldcollisioncallback_lastbody = NULL;
}
float _CDECL HeightFieldRaycast::newtonRaycastFilter(const NewtonBody* body, const float* hitNormal, int collisionID, void* userData, float intersectParam)
{
// get our object!
HeightFieldRaycast* me = (HeightFieldRaycast*)userData;
Body* bod = (Body*)NewtonBodyGetUserData( body );
const World* world = bod->getWorld();
Ogre::Vector3 normal = Ogre::Vector3( hitNormal[0], hitNormal[1], hitNormal[2] );
if(me->m_heightfieldcollisioncallback_bodyalreadyadded)
return intersectParam;
if( world->getDebugger().isRaycastRecording() && world->getDebugger().isRaycastRecordingHitBodies() )
{
world->getDebugger().addHitBody(bod);
}
if (me->userCallback( bod, intersectParam, normal, collisionID ))
return intersectParam;
else
return 1.1f;
}
unsigned _CDECL HeightFieldRaycast::newtonRaycastPreFilter(const NewtonBody *body, const NewtonCollision *collision, void* userData)
{
// get our object!
HeightFieldRaycast* me = (HeightFieldRaycast*)userData;
Body* bod = (Body*)NewtonBodyGetUserData( body );
const World* world = bod->getWorld();
me->m_heightfieldcollisioncallback_bodyalreadyadded = false;
me->m_heightfieldcollisioncallback_lastbody = bod;
if (me->userPreFilterCallback( bod ))
return 1;
else
{
if( world->getDebugger().isRaycastRecording() && world->getDebugger().isRaycastRecordingHitBodies() )
{
world->getDebugger().addDiscardedBody(bod);
}
return 0;
}
}
//--------------------------------
BasicRaycast::BasicRaycastInfo::BasicRaycastInfo()
{
mBody = NULL;
mDistance = -1.0;
mNormal = Ogre::Vector3::ZERO;
}
BasicRaycast::BasicRaycastInfo::~BasicRaycastInfo() {}
BasicRaycast::BasicRaycast() {}
BasicRaycast::BasicRaycast(const OgreNewt::World* world, const Ogre::Vector3& startpt, const Ogre::Vector3& endpt, bool sorted)
: TreeRaycast(), HeightFieldRaycast()
{
go( world, startpt, endpt, sorted );
}
void BasicRaycast::go(const OgreNewt::World* world, const Ogre::Vector3& startpt, const Ogre::Vector3& endpt, bool sorted)
{
// clean the list each time this function is called this way it can be re used for multiple casting.
mRayList.clear();
TreeRaycast::go( world, startpt, endpt );
HeightFieldRaycast::go( world, startpt, endpt );
if( sorted )
{
std::sort(mRayList.begin(), mRayList.end());
}
}
BasicRaycast::~BasicRaycast() {}
int BasicRaycast::getHitCount() const { return (int)mRayList.size(); }
BasicRaycast::BasicRaycastInfo BasicRaycast::getFirstHit() const
{
//return the closest hit...
BasicRaycast::BasicRaycastInfo ret;
Ogre::Real dist = Ogre::Math::POS_INFINITY;
RaycastInfoList::const_iterator it;
for (it = mRayList.begin(); it != mRayList.end(); it++)
{
if (it->mDistance < dist)
{
dist = it->mDistance;
ret = (*it);
}
}
return ret;
}
BasicRaycast::BasicRaycastInfo BasicRaycast::getInfoAt( unsigned int hitnum ) const
{
if (hitnum < mRayList.size())
{
return mRayList.at(hitnum);
}
else
{
BasicRaycast::BasicRaycastInfo emptyInfo;
return emptyInfo;
}
}
bool BasicRaycast::userCallback( OgreNewt::Body* body, Ogre::Real distance, const Ogre::Vector3& normal, int collisionID )
{
// create a new infor object.
BasicRaycast::BasicRaycastInfo newinfo;
newinfo.mBody = body;
newinfo.mDistance = distance;
newinfo.mNormal = normal;
newinfo.mCollisionID = collisionID;
mRayList.push_back( newinfo );
return false;
}
} // end NAMESPACE OgreNewt
Hey, I've got it compiled without error, but I still get no contact with the terrain. For the treecollision the contact works.
see code in: OgreNewt_CollisionPrimitives.cpp
float _CDECL HeightField::newtonRayCastCallback(const NewtonBody* const body, const NewtonCollision* const heightFieldCollision, dFloat interception, int row, int col, dFloat* normal, int faceId, void* usedData)
{
Body* bod = ((HeightFieldRaycast*)usedData)->m_heightfieldcollisioncallback_lastbody;
//! TODO: what do we need to return here?
if(!bod)
return 0;
((HeightFieldRaycast*)usedData)->userCallback( bod, interception, Ogre::Vector3(normal[0], normal[1], normal[2]), faceId );
((HeightFieldRaycast*)usedData)->m_heightfieldcollisioncallback_bodyalreadyadded = true;
return interception;
}
void HeightField::setRayCastCallbackactive(bool active, const NewtonCollision *col )
{
if(active)
NewtonHeightFieldSetUserRayCastCallback(col, newtonRayCastCallback);
else
NewtonHeightFieldSetUserRayCastCallback(col, NULL);
}
and in OgreNewt_RayCast.h:
friend float CollisionPrimitives::HeightField::newtonRayCastCallback(const NewtonBody* const body, const NewtonCollision* const heightFieldCollision, dFloat interception, int row, int col, dFloat* normal, int faceId, void* usedData);
I changed everything important in the other *.h files too.
Chookaa
25-12-2010 02:58:27
i pretty much left Raycast as it was except for declaring the friend function like you did and in my HeightField class i have
float _CDECL HeightField::newtonRayCastCallback(const NewtonBody* const body, const NewtonCollision* const heightField, dFloat interception, int row, int col, dFloat* normal, int faceId, void* userData)
{
NewtonBody* bod = NewtonBodyGetUserData(body);
((Raycast*)userData)->userCallback( bod, interception, Ogre::Vector3(normal[0], normal[1], normal[2]), faceId );
((Raycast*)userData)->m_treecollisioncallback_bodyalreadyadded = true;
return interception;
}
sorry im not that much help atm, my vs2010 crashed and killed every one of my project files that were loaded. it didn't loose any source files just the project files became corrupt and wont load. i'll be a couple of days sorting things back to vs2008 as vs2010 is proving to be more hassle than its worth atm. it's nicer to look at but intellisense is slow and the constant crashes and BSOD's are driving me nuts.
Chookaa
25-12-2010 23:57:19
yep it works for me.
i didnt create a HeightField raycast i just added
friend float CollisionPrimitives::HeightField::newtonRayCastCallback(const NewtonBody* const body, const NewtonCollision* const heightFieldCollision, dFloat interception, int row, int col, dFloat* normal, int faceId, void* usedData);
re: crash, i got most of my stuff working again, but now with vs2008, i'll give vs2010 a miss till a service pack comes out for it.