TreeCollision Scaling Problem

dizlexik

04-05-2007 21:18:30

It seems that when a SceneNode is parsed by TreeCollision it doesn't take into account the scaling of the SceneNode.
I have a SceneNode that I scale to Vector3(2, 1, 1) and then parse it with TreeCollision. When I turn on the debug lines you can see that the rigid body created is only half as wide as the rendered model because it wasn't scaled.
Can I scale the body somehow? Or is there some way to make the parser take scaling into account? Or is this just a bug that I'll have to wait to get fixed?

Thanks

pra

06-05-2007 16:38:54

that's strange... are you sure you parse it AFTER scaling?
this works perfectly for me, some days ago I coded a scaling function for my editor, after scaling it reparses the scenenode, and then the debug lines show me a perfect scaled body...

\€: are you using TreeCollision or TreeCollisionSceneParser?
the second one seems to actually have problems with scale...

pra

06-05-2007 18:05:01

OK, there IS a scaling bug, here's the proof:
I use the dotScene parsing code from the ogre wiki, and want to create trecollision with TreeCollisionSceneParser. I have a simpe .scene file with an ogre head and a box.
unscaled:

with debug lines:


and now scaled by 0.1

looks the same? debug lines on:

that's not all: the ogre head is actually scaled by (1,2,1) or (0.1,0.2,0.1).

here another screenshot, with ogrehead being scaled by (2,1,1):



I guess (without having actual idea) it has something to do with the scale being multiplied with the position in the ogrenewt code. I do not know for sure, but i think somewhere the node's own scale is used instead of the parent's scale...

I guess we have to wait for walaber to fix it...

\€: done with TreeCollisionSceneParser, latest from CVS

walaber

06-05-2007 21:41:57

I don't have much time to work on OgreNewt. if someone can find the problem and fix it, I will update OgreNewt and update CVS and my website!

pra

06-05-2007 22:08:46

considering that it's alerady late here, and that it's my birthsday today, i shouldn't do this, but i can't stop once i started :( :lol:

well, i THINK this works (at least it works for me)

OgreNewt_CollisionPrimitives.h, line 295:
void _parseNode( Ogre::SceneNode* node, const Ogre::Quaternion& curOrient, const Ogre::Vector3& curPos, Ogre::Vector3 parentScale = Ogre::Vector3::UNIT_SCALE );

OgreNewt_CollisionPrimitives.cpp, line 471:
(i made little changes in several parts, i'm too lazy to tell the exact locations now, so here's the whole function)
void TreeCollisionSceneParser::_parseNode(Ogre::SceneNode *node, const Ogre::Quaternion &curOrient, const Ogre::Vector3 &curPos, Ogre::Vector3 parentScale )
{
// parse this scene node.
// do children first.
Ogre::Quaternion thisOrient = curOrient * node->getOrientation();
/*Ogre::Vector3 thisPos = curPos + (curOrient * node->getPosition() * node->getScale());*/
Ogre::Vector3 thisPos = curPos + (curOrient * node->getPosition() * parentScale );
Ogre::Vector3 thisScale = node->getScale();

Ogre::SceneNode::ChildNodeIterator child_it = node->getChildIterator();

while (child_it.hasMoreElements())
{
_parseNode( (Ogre::SceneNode*)child_it.getNext(), thisOrient, thisPos, thisScale*parentScale );
}


// now add the polys from this node.
//now get the mesh!
unsigned int num_obj = node->numAttachedObjects();
for (unsigned int co=0; co<num_obj; co++)
{
Ogre::MovableObject* obj = node->getAttachedObject(co);
if (obj->getMovableType() != "Entity")
continue;

Ogre::Entity* ent = (Ogre::Entity*)obj;

if (!entityFilter(node, ent))
continue;

Ogre::MeshPtr mesh = ent->getMesh();

//find number of sub-meshes
unsigned short sub = mesh->getNumSubMeshes();

for (unsigned short cs=0;cs<sub;cs++)
{
Ogre::SubMesh* sub_mesh = mesh->getSubMesh(cs);

//vertex data!
Ogre::VertexData* v_data;

if (sub_mesh->useSharedVertices)
{
v_data = mesh->sharedVertexData;
}
else
{
v_data = sub_mesh->vertexData;
}

//let's find more information about the Vertices...
Ogre::VertexDeclaration* v_decl = v_data->vertexDeclaration;
const Ogre::VertexElement* p_elem = v_decl->findElementBySemantic( Ogre::VES_POSITION );

// get pointer!
Ogre::HardwareVertexBufferSharedPtr v_sptr = v_data->vertexBufferBinding->getBuffer( p_elem->getSource() );
unsigned char* v_ptr = static_cast<unsigned char*>(v_sptr->lock( Ogre::HardwareBuffer::HBL_READ_ONLY ));

//now find more about the index!!
Ogre::IndexData* i_data = sub_mesh->indexData;
size_t index_count = i_data->indexCount;
size_t poly_count = index_count / 3;

// get pointer!
Ogre::HardwareIndexBufferSharedPtr i_sptr = i_data->indexBuffer;

// 16 or 32 bit indices?
bool uses32bit = ( i_sptr->getType() == Ogre::HardwareIndexBuffer::IT_32BIT );
unsigned long* i_Longptr;
unsigned short* i_Shortptr;

if ( uses32bit)
{
i_Longptr = static_cast<unsigned long*>(i_sptr->lock( Ogre::HardwareBuffer::HBL_READ_ONLY ));
}
else
{
i_Shortptr = static_cast<unsigned short*>(i_sptr->lock( Ogre::HardwareBuffer::HBL_READ_ONLY ));
}

//now loop through the indices, getting polygon info!
int i_offset = 0;

for (size_t i=0; i<poly_count; i++)
{
Ogre::Vector3 poly_verts[3];
unsigned char* v_offset;
float* v_Posptr;
int idx;

if (uses32bit)
{
for (int j=0;j<3;j++)
{
idx = i_Longptr[i_offset+j]; // index to first vertex!
v_offset = v_ptr + (idx * v_sptr->getVertexSize());
p_elem->baseVertexPointerToElement( v_offset, &v_Posptr );
//now get vertex position from v_Posptr!
poly_verts[j].x = *v_Posptr; v_Posptr++;
poly_verts[j].y = *v_Posptr; v_Posptr++;
poly_verts[j].z = *v_Posptr; v_Posptr++;

poly_verts[j] = thisPos + (thisOrient * (poly_verts[j] * thisScale * parentScale));
}
}
else
{
for (int j=0;j<3;j++)
{
idx = i_Shortptr[i_offset+j]; // index to first vertex!
v_offset = v_ptr + (idx * v_sptr->getVertexSize());
p_elem->baseVertexPointerToElement( v_offset, &v_Posptr );
//now get vertex position from v_Posptr!

// switch poly winding.
poly_verts[j].x = *v_Posptr; v_Posptr++;
poly_verts[j].y = *v_Posptr; v_Posptr++;
poly_verts[j].z = *v_Posptr; v_Posptr++;

poly_verts[j] = thisPos + (thisOrient * (poly_verts[j] * thisScale * parentScale));
}
}

addPoly( poly_verts, getID(node, ent, cs) );
i_offset += 3;
}

//unlock the buffers!
v_sptr->unlock();
i_sptr->unlock();

}
}

}


it's all about the parentScale param, it should be the scale of all previous parents

pra

07-05-2007 21:49:13

ok, it doesn't work.
if the main node is not at Vector3::ZERO and Quaternion::IDENTITY, the whole thing becomes a mess...

\€: i think node->getWorldTransforms() is the key. too bad i have no idea about matrices...

\€2: no, the "getWorld*" stuff isn't good, it has to be relative to the current parent node.

almost there, i think... subtracting the main node's position fixed the positioning problem... i guess I have to do the same with the orientation, but rootOrientation.Inverse() seems not to do what I want, neither does rootOrientation * -1...

pra

08-05-2007 20:24:43

Triplepost FTW!
but i think i did it now...
in OgreNewt_CollisonPrimitives.h
void _parseNode( Ogre::SceneNode* node, const Ogre::Quaternion& curOrient, const Ogre::Vector3& curPos, Ogre::Vector3& curScale, bool rootNode = false );

in OgreNewt_collisionprimitives.cpp:
void TreeCollisionSceneParser::parseScene( Ogre::SceneNode *startNode, bool optimize)
{
count = 0;

start();

// parse the individual nodes.
Ogre::Quaternion rootOrient = Ogre::Quaternion::IDENTITY;
Ogre::Vector3 rootPos = Ogre::Vector3::ZERO;
Ogre::Vector3 rootScale = Ogre::Vector3::UNIT_SCALE;

_parseNode( startNode, rootOrient, rootPos, rootScale, true );

finish( optimize );
}

and

void TreeCollisionSceneParser::_parseNode(Ogre::SceneNode *node, const Ogre::Quaternion &curOrient, const Ogre::Vector3 &curPos, Ogre::Vector3 &curScale, bool rootNode )
{
// parse this scene node.
// do children first.
Ogre::Quaternion thisOrient;
Ogre::Vector3 thisPos;
Ogre::Vector3 thisScale = node->getScale()*curScale;
if(!rootNode)
{
//regular behaviour
thisOrient = curOrient * node->getOrientation();
thisPos = curPos + (curOrient * node->getPosition() * curScale );
}
else
{
//do not use the node's position and orientation,
//because it's all relative to it
thisOrient = curOrient;
thisPos = curPos;
}



Ogre::SceneNode::ChildNodeIterator child_it = node->getChildIterator();

while (child_it.hasMoreElements())
{
_parseNode( (Ogre::SceneNode*)child_it.getNext(), thisOrient, thisPos, thisScale );
}


// now add the polys from this node.
//now get the mesh!
unsigned int num_obj = node->numAttachedObjects();
for (unsigned int co=0; co<num_obj; co++)
{
Ogre::MovableObject* obj = node->getAttachedObject(co);
if (obj->getMovableType() != "Entity")
continue;

Ogre::Entity* ent = (Ogre::Entity*)obj;

if (!entityFilter(node, ent))
continue;

Ogre::MeshPtr mesh = ent->getMesh();

//find number of sub-meshes
unsigned short sub = mesh->getNumSubMeshes();

for (unsigned short cs=0;cs<sub;cs++)
{
Ogre::SubMesh* sub_mesh = mesh->getSubMesh(cs);

//vertex data!
Ogre::VertexData* v_data;

if (sub_mesh->useSharedVertices)
{
v_data = mesh->sharedVertexData;
}
else
{
v_data = sub_mesh->vertexData;
}

//let's find more information about the Vertices...
Ogre::VertexDeclaration* v_decl = v_data->vertexDeclaration;
const Ogre::VertexElement* p_elem = v_decl->findElementBySemantic( Ogre::VES_POSITION );

// get pointer!
Ogre::HardwareVertexBufferSharedPtr v_sptr = v_data->vertexBufferBinding->getBuffer( p_elem->getSource() );
unsigned char* v_ptr = static_cast<unsigned char*>(v_sptr->lock( Ogre::HardwareBuffer::HBL_READ_ONLY ));

//now find more about the index!!
Ogre::IndexData* i_data = sub_mesh->indexData;
size_t index_count = i_data->indexCount;
size_t poly_count = index_count / 3;

// get pointer!
Ogre::HardwareIndexBufferSharedPtr i_sptr = i_data->indexBuffer;

// 16 or 32 bit indices?
bool uses32bit = ( i_sptr->getType() == Ogre::HardwareIndexBuffer::IT_32BIT );
unsigned long* i_Longptr;
unsigned short* i_Shortptr;

if ( uses32bit)
{
i_Longptr = static_cast<unsigned long*>(i_sptr->lock( Ogre::HardwareBuffer::HBL_READ_ONLY ));
}
else
{
i_Shortptr = static_cast<unsigned short*>(i_sptr->lock( Ogre::HardwareBuffer::HBL_READ_ONLY ));
}

//now loop through the indices, getting polygon info!
int i_offset = 0;

for (size_t i=0; i<poly_count; i++)
{
Ogre::Vector3 poly_verts[3];
unsigned char* v_offset;
float* v_Posptr;
int idx;

if (uses32bit)
{
for (int j=0;j<3;j++)
{
idx = i_Longptr[i_offset+j]; // index to first vertex!
v_offset = v_ptr + (idx * v_sptr->getVertexSize());
p_elem->baseVertexPointerToElement( v_offset, &v_Posptr );
//now get vertex position from v_Posptr!
poly_verts[j].x = *v_Posptr; v_Posptr++;
poly_verts[j].y = *v_Posptr; v_Posptr++;
poly_verts[j].z = *v_Posptr; v_Posptr++;

poly_verts[j] = thisPos + (thisOrient * (poly_verts[j] * thisScale));
}
}
else
{
for (int j=0;j<3;j++)
{
idx = i_Shortptr[i_offset+j]; // index to first vertex!
v_offset = v_ptr + (idx * v_sptr->getVertexSize());
p_elem->baseVertexPointerToElement( v_offset, &v_Posptr );
//now get vertex position from v_Posptr!

// switch poly winding.
poly_verts[j].x = *v_Posptr; v_Posptr++;
poly_verts[j].y = *v_Posptr; v_Posptr++;
poly_verts[j].z = *v_Posptr; v_Posptr++;

poly_verts[j] = thisPos + (thisOrient * (poly_verts[j] * thisScale));
}
}

addPoly( poly_verts, getID(node, ent, cs) );
i_offset += 3;
}

//unlock the buffers!
v_sptr->unlock();
i_sptr->unlock();

}
}

}

This seems to work with nested nodes with the parent one being scaled, rotated and moved around. I hope i won't find anymore errors, or walaber will have time to fix them himself^^

btw, one thing i didn't understand: why Ogre::Vector3&? I always thought you do this to make the function return more than one value. I just made curScale be the same as curPos and curOrient

walaber

18-06-2007 01:44:19

this fix has been applied to the latest version of OgreNewt.

zuur

05-03-2008 01:15:00

This still isn't right btw;

If you create a SceneNode x with a mesh attached, and scale it, then pass x to TreeCollisionSceneParser, the scaling is wrong (not there at all I think).

If you create a SceneNode x with a child SceneNode y, attach the mesh to y, but scale x and pass x to TreeCollisionSceneParser, it works..

eduardo777

27-11-2009 22:07:25

Thanks its work :)