Recreating a shape [solved] + a scaling body/actor example

nargil

23-10-2008 00:58:04

Solved
_________________________________________
solution: the usage of nxv.cross() was wrong! It should be .dot(). The return value of NxVec3.dot/cross confused me.

At least you guys have now an almost working (you know what to fix) of scaling a body/actor (not working for convex/triangle yet) ;)
_________________________________________
[color=red][size=200]Click here to see a working example[/size][/color]


I'm scaling a body (actor) so I need to recreate its shapes

it->first-> is NxOgre::Body*
void cSelekcja::skaluj(Ogre::Vector3 skala)
{
NxActor* actor;
NxShape* shape;

NxU32 flags;
NxOgre::ShapeParams sp;


std::vector<BodyVec>::iterator it;
for(it = this->obiekty.begin(); it!=this->obiekty.end();it++)
{
actor = it->first->getNxActor();
for(unsigned int i=0; i<actor->getNbShapes(); i++)
{
shape = actor->getShapes()[0];
std::cout << "\n\n\n skaluje \n\n";
sp.setToDefault();

flags = 0;
for(int j=0; j<=20; j++)
{
if(shape->getFlag((NxShapeFlag)(1<<j))) flags+=(1<<j);
}
sp.mClothFlags.fromNxU32(flags);
sp.mFluidFlags.fromNxU32(flags);
sp.mShapeFlags.fromNxU32(flags);
sp.mSoftBodyFlags.fromNxU32(flags);

sp.mGroup = shape->getGroup();
sp.mGroupsMask = shape->getGroupsMask();
sp.mLocalPose.M = shape->getLocalOrientation();
NxVec3 nxv;
nxv.cross(NxOgre::NxConvert<NxVec3, Ogre::Vector3>(skala),shape->getLocalPosition());
sp.mLocalPose.t.set(nxv);
sp.mMass = actor->getMass() / (NxReal)actor->getNbShapes();
sp.mMaterial = shape->getMaterial();
//sp.mSkeleton._First->acquire(shape->getCCDSkeleton());
sp.mSkinWidth = shape->getSkinWidth();

if(shape->isBox())
{
nxv.cross(NxOgre::NxConvert<NxVec3, Ogre::Vector3>(skala), shape->isBox()->getDimensions());
it->first->addShape(new NxOgre::Cube(nxv, sp));
}
else if(shape->isSphere()) it->first->addShape(new NxOgre::Sphere(shape->isSphere()->getRadius()*skala.length(),sp));
else if(shape->isCapsule()) it->first->addShape(new NxOgre::Capsule(shape->isCapsule()->getRadius()*skala.length(),shape->isCapsule()->getHeight()*skala.y,sp));

it->first->removeShape((NxOgre::NxShapeIndex)0);
//actor->releaseShape(*shape);
}
}
}


skaluje

PhysX Error! NXE_INVALID_PARAMETER (f:\scmvista\experimental\PhysX_2.8.1_GPU\nov
odex\SDKs\Physics\src\NpActor.cpp:602)
Actor::createShape: desc.isValid() fails!
[NxOgre] NULL or invalid shape was attempted to be assigned to this shape-
[NxOgre] 'NxOgre-Shape'.


from what I see
NxOgreShapePrimitives.cpp
at void Cube::createShape(NxActor* actor, NxShapeIndex index, Scene* scene) {
(...)
NxShape* shape = actor->createShape(mShapeDescription);
(...)
returns 0.
mShapeDescription.NxShapeDesc.ccdSkeleton == 0
mShapeDescription.NxShapeDesc.name == 0



Is that the case ? How do I create a proper skeleton / name for it ? Or maybe am I passing somewhere a wrong pointer/value ?

crioto

23-10-2008 11:57:50

offtopic: (Looking at screenshot) What the debugger do you use?

betajaen

23-10-2008 12:22:30

Visual Studio.

nargil

23-10-2008 20:53:57

Know my kindness you unworthy mortals! xD

Here is a working example on How to scale a body/actor (many people ask for it). It only supports box,sphere and capsule shapes. Convex, triangle aren't and won't be supported - you have flour for it. Wheels can be easily added (I think), but I don't need them, so I will not write it for you.


//replacy NxOgre::Body* with NxOgre::Actor* if you need
void scaleBody(NxOgre::Body* NxOgreBody, Ogre::Vector3 scale)
{
bool cancel;
NxActor* myNxActor;
NxShape* myNxShape;
Ogre::SceneNode* sn;
Ogre::Vector3 ovec;

NxU32 flags;
NxOgre::ShapeParams sp;
NxVec3 nxvec;

cancel = false;
myNxActor = NxOgreBody->getNxActor();
for(unsigned int i=0; i<myNxActor->getNbShapes(); i++)
{
myNxShape = myNxActor->getShapes()[0];
sp.setToDefault();

flags = 0;
for(int j=0; j<=20; j++) //this is how NxShapeFlags are defined. Look at c:\program files\nvidia corporation\nvidia physx sdk\v2.8.1\sdks\physics\include\Nxp.h line:403
{
if(myNxShape->getFlag((NxShapeFlag)(1<<j))) flags+=(1<<j);
}
sp.mClothFlags.fromNxU32(flags);
sp.mFluidFlags.fromNxU32(flags);
sp.mShapeFlags.fromNxU32(flags);
sp.mSoftBodyFlags.fromNxU32(flags);

sp.mGroup = myNxShape->getGroup();
sp.mGroupsMask = myNxShape->getGroupsMask();
sp.mLocalPose.M = myNxShape->getLocalOrientation();

nxvec = myNxShape->getLocalPosition();
nxvec.x*=scale.x;
nxvec.y*=scale.y;
nxvec.z*=scale.z;
sp.mLocalPose.t.set(nxvec);

//actually I didn't find any better solution for the shape mass, but I really don't know if thats importatnt.
sp.mMass = myNxActor->getMass() / (NxReal)myNxActor->getNbShapes();

sp.mMaterial = myNxShape->getMaterial();

//I don't know how to copy a CCDSkeleton. The following line is crashing, so it's commented out.
//sp.mSkeleton._First->acquire(myNxShape->getCCDSkeleton());

sp.mSkinWidth = myNxShape->getSkinWidth();

if(myNxShape->isBox())
{
nxvec=myNxShape->isBox()->getDimensions(); // this get's just the half size, so you see *2 down here
nxvec.x*=scale.x *2;
nxvec.y*=scale.y *2;
nxvec.z*=scale.z *2;
if(nxvec.x <=0) cancel=true;
else if(nxvec.y <=0) cancel=true;
else if(nxvec.z <=0) cancel=true;
else NxOgreBody->addShape(new NxOgre::Cube(nxvec, sp));
}
else if(myNxShape->isSphere())
{
//we find the most differing (from 1.0f) scale coordinate to scale the radius
float scaleF = 1.0f;
if(Ogre::Math::Abs(scale.x-1.0f) >= Ogre::Math::Abs(scale.y-1.0f)
&& Ogre::Math::Abs(scale.x-1.0f) >= Ogre::Math::Abs(scale.z-1.0f)) scaleF = scale.x;
else if(Ogre::Math::Abs(scale.y-1.0f) >= Ogre::Math::Abs(scale.x-1.0f)
&& Ogre::Math::Abs(scale.y-1.0f) >= Ogre::Math::Abs(scale.z-1.0f)) scaleF = scale.y;
else if(Ogre::Math::Abs(scale.z-1.0f) >= Ogre::Math::Abs(scale.y-1.0f)
&& Ogre::Math::Abs(scale.z-1.0f) >= Ogre::Math::Abs(scale.x-1.0f)) scaleF = scale.z;
if(scaleF<=0) cancel=true;
else NxOgreBody->addShape(new NxOgre::Sphere(myNxShape->isSphere()->getRadius()*scaleF,sp));
}
else if(myNxShape->isCapsule())
{
float scaleF = 1.0f;
//same as with Sphere, but we
if(Ogre::Math::Abs(scale.x-1.0f) >= Ogre::Math::Abs(scale.z-1.0f)) scaleF = scale.x;
else scaleF = scale.z;

if(scaleF<=0 || scale.y<=0) cancel=true;
else NxOgreBody->addShape(new NxOgre::Capsule(myNxShape->isCapsule()->getRadius()*scaleF,myNxShape->isCapsule()->getHeight()*scale.y,sp));
}

NxOgreBody->removeShape((NxOgre::NxShapeIndex)0);
}
if(!cancel) //comment out this block of code if you scale an actor - not a body
{
sn = ((NxOgre::OgreNodeRenderable*)(NxOgreBody)->getRenderable())->getNode();
ovec = sn->getScale();
ovec*=scale;
sn->setScale(ovec);
}
}


All I want for this piece of code is your soul <evil laugh>. You may add it to your application / library (maybe NxOgre - hmmm betajean ?), and don't even mention my name (claim it's your code - then I get your soul ! xD).

Known bugs: if you scale an actor with more than 1 shape - it can happen that one shape would be too small for scaling it down, but the rest of the shapes will be scaled. So there can be some disproportion.

betajaen

23-10-2008 21:03:30

Hate to rain on your code there, but with NxOgre1.0'T5 and using NxOgre's helpers functions. It can be roughly reduced to.

void scaleBody(NxOgre::Body* body, Ogre::Vector3 scale)
{
static_cast<OgreNodeRenderable*>(body->getRenderable())->setScale(scale);
float mass = mActor->getMass();
Actor::CollisionModel shapes = mActor->getCollisionModel();
for (Shape* shape = shapes.Begin();shape = shapes.Next();)
actor->setDimensions(scale);
mActor->getNxActor()->updateMassFromShapes(0, mass);
}


:D

nargil

23-10-2008 21:09:38

whats this:
actor->setDimensions(scale)

?

nargil

23-10-2008 21:49:19

Ok. Upgraded version. Don't tested yet.

using namespace NxOgre;

void scaleShape(NxOgre::Shape* shape, NxVec3 scale)
{
NxVec3 nxvec;

nxvec = shape->mNxShape->getLocalPosition();
nxvec.x*=scale.x;
nxvec.y*=scale.y;
nxvec.z*=scale.z;
shape->mNxShape->setLocalPosition(nxvec);

if(shape->mNxShape->isBox())
{
nxvec = shape->mNxShape->isBox()->getDimensions();
nxvec.x*=scale.x;
nxvec.y*=scale.y;
nxvec.z*=scale.z;
if(nxvec.x <=0) return;
else if(nxvec.y <=0) return;
else if(nxvec.z <=0) return;
shape->mNxShape->isBox()->setDimensions(nxvec);
}
else if(shape->mNxShape->isSphere())
{
float scaleF = 1.0f;
if(Ogre::Math::Abs(scale.x-1.0f) >= Ogre::Math::Abs(scale.y-1.0f)
&& Ogre::Math::Abs(scale.x-1.0f) >= Ogre::Math::Abs(scale.z-1.0f)) scaleF = scale.x;
else if(Ogre::Math::Abs(scale.y-1.0f) >= Ogre::Math::Abs(scale.x-1.0f)
&& Ogre::Math::Abs(scale.y-1.0f) >= Ogre::Math::Abs(scale.z-1.0f)) scaleF = scale.y;
else if(Ogre::Math::Abs(scale.z-1.0f) >= Ogre::Math::Abs(scale.y-1.0f)
&& Ogre::Math::Abs(scale.z-1.0f) >= Ogre::Math::Abs(scale.x-1.0f)) scaleF = scale.z;

scaleF*= shape->mNxShape->isSphere()->getRadius();
if(scaleF <=0) return;
shape->mNxShape->isSphere()->setRadius(scaleF);
}
else if(shape->mNxShape->isCapsule())
{
float scaleF = 1.0f;
if(Ogre::Math::Abs(scale.x-1.0f) >= Ogre::Math::Abs(scale.z-1.0f)) scaleF = shape->mNxShape->isCapsule()->getRadius() * scale.x;
else scaleF = shape->mNxShape->isCapsule()->getRadius() * scale.z;

scale.y*=shape->mNxShape->isCapsule()->getHeight();

if(scaleF<=0 || scale.y<=0) return;
shape->mNxShape->isCapsule()->setDimensions(scaleF, scale.y);
}
}

void scaleBody(NxOgre::Body* body, Ogre::Vector3 scale)
{
static_cast<OgreNodeRenderable*>(body->getRenderable())->setScale(scale);
float mass = body->getMass();
Actor::CollisionModel shapes = body->getCollisionModel();
for (NxOgre::Shape* shape = shapes.Begin();shape = shapes.Next();)
{
scaleShape(shape,NxConvert<NxVec3,Ogre::Vector3>(scale));
}
body->getNxActor()->updateMassFromShapes(0, mass);
}


Pros:
- no deleting, adding shapes
- no problems with CCDSkeleton

lets see if that works too :)

EDIT: Works now

betajaen

23-10-2008 22:14:12

I meant shape->setDimensions(...), which basically does what your scaleShape does.

nargil

23-10-2008 22:21:16

maybe I'm using a different 1.0'22 T5, but there is no setDimension() in shape-> ;)

betajaen

23-10-2008 22:34:26

Urgh. There is in Cube/Sphere/Capsule though. :P