Common library with physics engine

What it says on the tin: a place to discuss proposed new features.
Post Reply
imguin
Gnoblar
Posts: 3
Joined: Fri Apr 04, 2008 9:36 pm

Common library with physics engine

Post by imguin »

I use OGRE and Bullet together. Both of these libraries have their own vector class. It would be much more easier and faster if they would use the same class. The same goes for angles.
It would be also good if they would have a common terrain and mesh class. To make a hull mesh in bullet I have to extract information from Ogre mesh and then create a bullet mesh from it. In the end it uses twice as much memory as needed and it is "slow". If they would have a common class, we could create a mesh and then send the pointer of the mesh to bullet.

The same goes for every other physic library. It would be great if these engines would make a common library containing these classes. Is it possible to cooperate with one of them?
User avatar
betajaen
OGRE Moderator
OGRE Moderator
Posts: 3447
Joined: Mon Jul 18, 2005 4:15 pm
Location: Wales, UK
x 58
Contact:

Post by betajaen »

It's very risky. But in PhysX and Ogre, the NxVec3 and Ogre::Vector3 classes are identical (from a variable point of view) - three floats. I've static_cast'd a NxVec3 into a Ogre::Vector3 function quite a few times and it's been fine.

I'm sure somebody will tell me that's a bad thing though.
User avatar
haffax
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 4823
Joined: Fri Jun 18, 2004 1:40 pm
Location: Berlin, Germany
x 8
Contact:

Post by haffax »

As long as neither is polymorphic I don't see a problem here. If the data maps, then just cast them and be done with it. 8)
team-pantheon programmer
creators of Rastullahs Lockenpracht
User avatar
PolyVox
OGRE Contributor
OGRE Contributor
Posts: 1316
Joined: Tue Nov 21, 2006 11:28 am
Location: Groningen, The Netherlands
x 18
Contact:

Post by PolyVox »

betajaen wrote:It's very risky. But in PhysX and Ogre, the NxVec3 and Ogre::Vector3 classes are identical (from a variable point of view) - three floats. I've static_cast'd a NxVec3 into a Ogre::Vector3 function quite a few times and it's been fine.

I'm sure somebody will tell me that's a bad thing though.
It's a bad thing to do! Well, there are various issues - firstly the internals of the classes may change though for something as simple as a vector this is probably not likely. Maybe it happens with matrices, quaternions, etc though. Secondly, what if the two libraries are compiled on different compilers, or on the same one but with different optimizations? This could have an effect on how the data is laid out. I'm sure that in reality it works fairly well, but it's still bad practice... :wink:

As for the original question... well yes the situation sucks. But it's not limited to Ogre and physics - it affects pretty much any large software system which involves integrating many components. In the case of Ogre and physics engines there can me many reasons why maths libraries are duplicated. Ther are licensing issues, slightly differing requirements ,coding standards, and good old NIH Syndrome.

Basically you should look into the Adapter (also known as Wrapper) pattern in the GoF book. Not there are two variants (object and class) which can be useful in difernt situations.
imguin
Gnoblar
Posts: 3
Joined: Fri Apr 04, 2008 9:36 pm

Post by imguin »

Thanks for the tips. static_cast works well with vectors but not with quoternions(sorry PolyVox). I know about wrappers, and I already have OgreBullet, but I always try to find a better way.
User avatar
chmod
Greenskin
Posts: 131
Joined: Tue Feb 25, 2003 10:33 pm
Location: Seattle, Washington USA

Post by chmod »

I just haul these inlines around in utils.h

Code: Select all

inline Ogre::Vector3 ogrevec(NxVec3 vec) {
	return Ogre::Vector3(vec.x, vec.y, vec.z);
}

inline NxVec3 nxvec(Ogre::Vector3 vec) {
	return NxVec3(vec.x, vec.y, vec.z);
}

inline Ogre::Quaternion ogrequat(NxQuat quat) {
	return Ogre::Quaternion(quat.w, quat.x, quat.y, quat.z);
}

inline NxQuat nxquat(Ogre::Quaternion quat) {
	NxQuat new_quat;
	new_quat.setWXYZ(quat.w, quat.x, quat.y, quat.z);
	return new_quat;
}
(for physx)
reptor
Ogre Magi
Posts: 1120
Joined: Wed Nov 15, 2006 7:41 pm
Location: Finland
x 5

Post by reptor »

The idea of having the same 3D mesh for visual and for physical representation of an object is often not good I think.

The problem is that the visual presentation often needs to be much more complex than what the physical representation needs to be. You should not give the physics engine any more complex a mesh than is necessary.

I have seen in commercial games this being done so that there are two or more versions of the same 3D model. One for visual and one for physical representation of the object.

The visual model can then have more versions, so-called LODs, level-of-details, which have reduced complexity compared to the first visual mesh. This is done to make it possible to dynamically select a less-complex mesh for display when game situation allows it. This results in better performance.

I have also seen meshes which are used only by Artificial Intelligence. View determination being an example.

My point here being, it is not possible to combine the visual and the physical 3D mesh but only in the most simple cases.
voxel
Gnome
Posts: 334
Joined: Wed Aug 02, 2006 9:27 am
Location: Toronto, Canada

Post by voxel »

reptor wrote:I have seen in commercial games this being done so that there are two or more versions of the same 3D model. One for visual and one for physical representation of the object.
I fully agree...

I use these conversion routines (unoptimized because I'm still early in my project):

Code: Select all

	inline Ogre::Vector3 toVector3(const btTransform& t)
	{
		Ogre::Vector3 v(t.getOrigin().getX(), t.getOrigin().getY(), t.getOrigin().getZ());
		return v;
	}

	inline Ogre::Vector3 toVector3(const btVector3& t)
	{
		Ogre::Vector3 v(t.getX(), t.getY(), t.getZ());
		return v;
	}

	inline btVector3 toVector3(const Ogre::Vector3& t)
	{
		btVector3 v(t.x, t.y, t.z);
		return v;
	}

	inline Ogre::Quaternion toQuaternion(const btQuaternion& q)
	{
		Ogre::Quaternion v(q.getW(),q.getX(), q.getY(), q.getZ());
		return v;
	}

	inline btQuaternion toQuaternion(const Ogre::Quaternion& q)
	{
		btQuaternion v(q.x, q.y, q.z, q.w);
		return v;
	}

	inline btTransform toTransform(const Ogre::SceneNode* node)
	{
		btTransform t;
		t.setIdentity();
		t.setOrigin(toVector3(node->getWorldPosition()));
		t.setRotation(toQuaternion(node->getWorldOrientation()));
		return t;
	}
Last edited by voxel on Tue Apr 08, 2008 6:44 am, edited 1 time in total.
btmorex
Gremlin
Posts: 156
Joined: Thu May 17, 2007 10:56 pm

Post by btmorex »

I do something similar that's probably less efficient, but makes my life easier. I just subclass Ogre::Vector3 and then use my own subclassed version everywhere with automatic conversions to bullet vectors.

Code: Select all

class vector3 : public Ogre::Vector3
{
public:
    vector3() : Ogre::Vector3(), m_valid(false) {}
    vector3(const Ogre::Vector3& v) : Ogre::Vector3(v), m_valid(true) {}
    vector3(const btVector3& v) : Ogre::Vector3(v.x(), v.y(), v.z()), m_valid(true) {}
    vector3(const real& x, const real& y, const real& z) : Ogre::Vector3(x, y, z), m_valid(true) {}

    operator bool() const
    {
        return m_valid;
    }

    operator btVector3() const
    {
        return btVector3(x, y, z);
    }

private:
    bool m_valid;
};
This allows me to use my vector3 wherever either an Ogre::Vector3 or a btVector3 is expected/returned.

You can ignore the m_valid stuff. I'll probably end up removing it, but I like the fact that I can test whether the vector was actually initialized with something.
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7157
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 538

Post by Kojack »

I use a template function:

Code: Select all

template <typename T1, typename T2>
   T1 convertVector3(const T2 &v)
   {
      T1 result;
      result.x = v.x;
      result.y = v.y;
      result.z = v.z;
      return result;
   }
It can convert any class with x,y,z components into any other class with x,y,z components, regardless of memory organisation, datatypes, extra members, etc.

So I can do:

Code: Select all

NxVec3 nv;
Ogre::Vector3 ov = convertVector3<Ogre::Vector3>(nv);
For all game stuff I use my own math classes (wrote part of them about a decade ago) and convert to/from ogre and other libs only when needed.


I was once looking at using Blitz++, it's the only independent math library I've seen which doesn't look painful to use. But it still didn't have all the features I wanted, and adding them would be hard because Blitz++ is a massively templated meta programmed library (think of Boost). Like all massively templated libraries, running in debug is like swimming in tar, but release builds run damn fast.
Although Blitz++ did give me the idea to let me initialise vectors like this:

Code: Select all

kf::Vector3 v = 0, 1, 0;
:)
imguin
Gnoblar
Posts: 3
Joined: Fri Apr 04, 2008 9:36 pm

Post by imguin »

I understand now the problems with using the same mesh. However I still believe it would be easier to use a common library (although I have every needed functions).
However, I see the problems, so I won't complain anymore.

Thanks for the codes, today I've learned about inline functions.

Kojack: I was curious, so I tried these out:

Code: Select all

        btVector3 test=1,1,1;
        Vector3 test=1,1,1;
Neither of them works. Maybe it's Blitz++ specific, or not supported by MingW.
User avatar
anomalous_underdog
Kobold
Posts: 30
Joined: Tue Aug 21, 2007 8:20 pm

Post by anomalous_underdog »

Kojack wrote: I was once looking at using Blitz++, it's the only independent math library I've seen which doesn't look painful to use. But it still didn't have all the features I wanted, and adding them would be hard because Blitz++ is a massively templated meta programmed library (think of Boost). Like all massively templated libraries, running in debug is like swimming in tar, but release builds run damn fast.
Although Blitz++ did give me the idea to let me initialise vectors like this:

Code: Select all

kf::Vector3 v = 0, 1, 0;
:)
damn that's weird c++ syntax. are you sure that's no typo? I tried looking at the Blitz++ homepage and I didn't see any mention of that
warmi
Gnoll
Posts: 674
Joined: Sun May 27, 2007 3:56 am
Location: USA

Post by warmi »

kf::Vector3 v = 0, 1, 0;
Yep it is weird.

It makes no real contribution but to confuse people.
CABAListic
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 2903
Joined: Thu Jan 18, 2007 2:48 pm
x 58
Contact:

Post by CABAListic »

Well, it's certainly possible to do that (so no typo), though I'd also advise to stay clear of such things. It seems more like a way to show how "clever" you can be with C++ without actually improving your code as such. It's still kind of cool technically :)
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

CABAListic wrote:Well, it's certainly possible to do that (so no typo), though I'd also advise to stay clear of such things. It seems more like a way to show how "clever" you can be with C++ without actually improving your code as such. It's still kind of cool technically :)
Doesn't 0, 1, 0 evaluate to 0? Shouldn't it be {0, 1, 0}? But then, Ogre::Vector3 has a constructor, which means you can't use array-initialization.
User avatar
betajaen
OGRE Moderator
OGRE Moderator
Posts: 3447
Joined: Mon Jul 18, 2005 4:15 pm
Location: Wales, UK
x 58
Contact:

Post by betajaen »

You could probably get away with overloading the "operator,(float)" and store them very temporarily in a static container somewhere but it would be very stupid; since it would overload everything with a float regardless if it used with a Vector3 or not.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

betajaen wrote:You could probably get away with overloading the "operator,(float)" and store them very temporarily in a static container somewhere but it would be very stupid; since it would overload everything with a float regardless if it used with a Vector3 or not.
Since when can you overload operators for built-in types :|
CABAListic
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 2903
Joined: Thu Jan 18, 2007 2:48 pm
x 58
Contact:

Post by CABAListic »

No, you need to overload the operator= of kf::Vector3 to accept an arbitrary helper type. This helper type must be constructible from float and provide an overload for operator,(float). So what the compiler then does is construct a Helper object which sequentially accepts additional float values via operator, then is assigned to kf::Vector3 which reads the first three stored values from it (similarly, kf::Vector4 would read the first four from it, etc.).
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

CABAListic wrote:No, you need to overload the operator= of kf::Vector3 to accept an arbitrary helper type. This helper type must be constructible from float and provide an overload for operator,(float). So what the compiler then does is construct a Helper object which sequentially accepts additional float values via operator, then is assigned to kf::Vector3 which reads the first three stored values from it (similarly, kf::Vector4 would read the first four from it, etc.).
:shock:

Oh, totally. That seems like a good coding practice! I love it. And I'm not being sarcastic or anything, come on now...
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7157
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 538

Post by Kojack »

Hehe.
I never use the v=0,1,0 syntax in my own code, it's just there to freak out all the c++ coders who don't understand "operator,". :)
(Which is a surprisingly large number of people)

Here's how I did it, no helper types needed:

Code: Select all

      inline Vector3T &operator=(T c)
      {
         x = c;
         y = c;
         z = c;
         return *this;
      }
      inline Vector3T &operator,(T c)
      {
         y=z;
         z=c;
         return *this;
      }
So when I do:
v = 1,2,3
the result is to first call operator= and set the vector to 1,1,1 and returns a reference to it. The first operator, takes the vector, shuffles z into y and puts 2 into z (vector is now 1,1,2). The second call to operator, shuffles z into y again, and puts 3 into z (vector is now 1,2,3). The commas actually directly operate on the variable on the left, rather than build an object on the right and assign it.

Boost uses the comma operator in assign, detail, iostreams, lambda, parameter, python, spirit, test and xpressive.
User avatar
betajaen
OGRE Moderator
OGRE Moderator
Posts: 3447
Joined: Mon Jul 18, 2005 4:15 pm
Location: Wales, UK
x 58
Contact:

Post by betajaen »

I've tried writing my own Boost style Parameter class once with the general usage being:

Code: Select all

Vector3 vec3 = Vector3((x = 10, z = 10.0f, y=13.0f, normalise = true));
I've managed to get "x=10" to compile and actually work, but I have never managed to use the "operator," correctly. With this little insight Kojack posted I'm going to have another stab at it. Actual documentation on the "operator," class is quite rare it seems.
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7157
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 538

Post by Kojack »

I still wish there was a whitespace operator. :)
User avatar
betajaen
OGRE Moderator
OGRE Moderator
Posts: 3447
Joined: Mon Jul 18, 2005 4:15 pm
Location: Wales, UK
x 58
Contact:

Post by betajaen »

Was?

Perhaps http://en.wikipedia.org/wiki/Whitespace ... _language) could be literally ported to C/C++ just using a white space operator.
User avatar
betajaen
OGRE Moderator
OGRE Moderator
Posts: 3447
Joined: Mon Jul 18, 2005 4:15 pm
Location: Wales, UK
x 58
Contact:

Post by betajaen »

Well thanks to Kojack and still being relativity inside the topic of this thread. I finally managed to complete my "Boost Parameters" classes and most likely drop the string param system from NxOgre.

Observe:

Code: Select all

using namespace Params;

// Only need to declare these once.
PARAM(Mass, float);
PARAM(Gravity, bool);
PARAM(x, float);
PARAM(y, float);
PARAM(z, float);

class Foo {

	public:

		void Bar(Params::Parameters p) {
			std::cout << "Number of Params = " << p.Params.size() << std::endl;
			for (int i=0;i < p.Params.size();i++)
				p.Params[i].debugPrint();
		}

};

void main() {

	Foo* foo = new Foo();
	foo->Bar((Mass = 10.0f, Gravity = false, x = 10.0f, z = 70.0f, y = 32.0f));
	delete foo;

}
Which outputs:

Code: Select all

Number of Params = 5
struct Params::_Identifiers::Mass -> 10
struct Params::_Identifiers::Gravity -> 0
struct Params::_Identifiers::x -> 10
struct Params::_Identifiers::z -> 70
struct Params::_Identifiers::y -> 32

Thanks Kojack! ;)
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

Kojack wrote:[...]
EDIT: Hold on, I'm just being a n00b :oops:. operator,() is #17 on the operator precedence list, it's always last. So the order is "((v=1),2),3", and not "v = (1, (2, 3))".
Post Reply