I can replicate this problem with almost all the collision manager methods.
My default setup:
* Metatriangle selector - total of 1500 triangles
- Triangle selector 1 - 500 triangles
- Triangle selector 2 - 1000 triangles
The issue arises when the nodes in the triangle selector are completely or are partially hidden.
Currently I see two main issues, both are related with the collision manager and the meta triangle selector classes:
Bug #1
The collision manager detects collision against the triangles within its range (line or bounding box). After collision has been detected requests the scenenode for the triangle using its index. (The index comes from the list of triangles within range/line/bbox) and tries to find the triangle id in the list with all triangles resulting that it finds a different triangle on that id.
I described two different lists of triangles the collision manager checks:
1. one which is filtered and contains the same or less triangles than list 2(<= 1500 triangles)
2. one which contains all the triangles (=1500 triangles)
If one of the scenenodes are partially or completely out of sight list 1 contains fewer triangles and thus the index won't be the same as the one in list 2.
Example for the onCollision method:
CSceneCollisionManager.h line 367, get a filtered list of triangles in range
Code: Select all
s32 cnt = 0;
selector->getTriangles(Triangles.pointer(), totalcnt, cnt, ray);
CSceneCollisionManager.h line 409, get triangle from list with all triangles where i is the index of the triangle from filtered list (list 1)
Code: Select all
selector->getSceneNodeForTriangle(i);
A logic change for me would be to include the same filters for the getSceneNodeForTriangle method, giving a ray or boundingbox with it as filter.
Code: Select all
selector->getSceneNodeForTriangle(i, ray);
Bug #2
There is also an error with the getSceneNodeForTriangle method in the CMetaTriangleSelector.h file:
Code: Select all
for (u32 i=0; i<TriangleSelectors.size(); ++i)
{
u32 totalTriangles += TriangleSelectors[i]->getTriangleCount();
if(totalTriangles > triangleIndex)
return TriangleSelectors[i]->getSceneNodeForTriangle(0);
}
The error here is that it doesn't pass the index of the triangle to the triangleselector but 0, if the child selector is a meta triangle selector too it will always return the first node it finds rather than the one matching.
One solution could be to give the correct triangle index:
Code: Select all
for (u32 i=0; i<TriangleSelectors.size(); ++i)
{
u32 triangles = TriangleSelectors[i]->getTriangleCount();
if(totalTriangles + triangles > triangleIndex)
return TriangleSelectors[i]->getSceneNodeForTriangle(triangleIndex - totalTriangles);
totalTriangles += triangles;
}
My current solution for the collisionmanager:
I created a second method getSceneNodefromTriangleIndex taking a line3df in account:
Code: Select all
//! Return the scene node associated with a given triangle in a filtered list with as filter the line3df
ISceneNode* CMetaTriangleSelector::getSceneNodeForTriangle(u32 triangleIndex, const core::line3d<f32>& line) const
{
u32 totalTriangles = 0;
for (u32 i=0; i<TriangleSelectors.size(); ++i)
{
//Get the list of triangles within reach of the line
s32 arraySize = TriangleSelectors[i]->getTriangleCount();
core::array<core::triangle3df> triangles;
triangles.set_used(arraySize);
s32 trianglesCnt;
TriangleSelectors[i]->getTriangles(triangles.pointer(), arraySize, trianglesCnt, line);
//Default picking based on triangle count, note: also reducing the index for the local selector, otherwise the next selector can's search a subset
if(totalTriangles + trianglesCnt > triangleIndex)
return TriangleSelectors[i]->getSceneNodeForTriangle(triangleIndex - totalTriangles, line);
totalTriangles += trianglesCnt;
}
// For lack of anything more sensible, the index is not here
return 0;
}
[edit] Added a solution from my custom irrlicht 1.8 build