Hi,
I have a problem. Lets say for example I have a tree node and a player node. How will you be able to tell the difference when using a ray to check if the mouse has hovered over them?. I thought of an idea and that was having the lower 16 bits of the nodeID as the object type and the upper 16 bits as the objectID. I think this is a bit hacky though
Any advice friends?
Thanks,
Dan
set a type to a SceneNode?
Re: set a type to a SceneNode?
what you describe is a perfectly normal method for doing this.
(warning : ramble in progress below)
personally..........
I use an object class to house a scenenode.
in that object class, I have an ID and a TYPE variable.
then I copied the function called getPickedNodeBB and made a new one called
void CSO_Editor::getPickedNodeBB(OBJECT_TYPE objecttype, ISceneNode* root,
core::line3df& ray, s32 bits, bool noDebugObjects,
f32& outbestdistance, ISceneNode*& outbestnode)
and just added a call to bool CSO_Editor::isSelectable(CSObject* obj, OBJECT_TYPE objecttype) in it.
I use it like this..........
the only part that needed changed was this part
(warning : ramble in progress below)
personally..........
I use an object class to house a scenenode.
in that object class, I have an ID and a TYPE variable.
then I copied the function called getPickedNodeBB and made a new one called
void CSO_Editor::getPickedNodeBB(OBJECT_TYPE objecttype, ISceneNode* root,
core::line3df& ray, s32 bits, bool noDebugObjects,
f32& outbestdistance, ISceneNode*& outbestnode)
and just added a call to bool CSO_Editor::isSelectable(CSObject* obj, OBJECT_TYPE objecttype) in it.
I use it like this..........
Code: Select all
//! Returns the nearest scene node which collides with a 3d ray and
//! which id matches a bitmask.
ISceneNode* CSO_Editor::getSceneNodeFromRayBB(OBJECT_TYPE objecttype,
const core::line3d<f32>& ray,
s32 idBitMask, bool noDebugObjects, scene::ISceneNode* root)
{
ISceneNode* best = 0;
f32 dist = FLT_MAX;
core::line3d<f32> truncatableRay(ray);
getPickedNodeBB(objecttype, (root == 0) ? getSmgr()->getRootSceneNode() : root, truncatableRay,
idBitMask, noDebugObjects, dist, best);
return best;
}
Code: Select all
CSObject* obj = getLevel()->getObjectFactory()->getObjectPointer(current->getID());
if ((noDebugObjects ? !current->isDebugObject() : true) &&
(isSelectable(obj, objecttype)))
Code: Select all
bool CSO_Editor::isSelectable(CSObject* obj, OBJECT_TYPE objecttype)
{
if (!obj) return false;
if (obj->getDebugObject()) return false;
if (obj->getObjectType() == objecttype) return true;
else return false;
}
//! recursive method for going through all scene nodes
void CSO_Editor::getPickedNodeBB(OBJECT_TYPE objecttype, ISceneNode* root,
core::line3df& ray, s32 bits, bool noDebugObjects,
f32& outbestdistance, ISceneNode*& outbestnode)
{
const ISceneNodeList& children = root->getChildren();
const core::vector3df rayVector = ray.getVector().normalize();
ISceneNodeList::ConstIterator it = children.begin();
for (; it != children.end(); ++it)
{
ISceneNode* current = *it;
if (current->isVisible())
{
// printf("ID = %d/n", current->getID());
CSObject* obj = getLevel()->getObjectFactory()->getObjectPointer(current->getID());
if ((noDebugObjects ? !current->isDebugObject() : true) &&
(isSelectable(obj, objecttype))) //(bits != 0 && (current->getID() & bits))))
// (bits == 0 || (isSelectable(obj, objecttype)))) //(bits != 0 && (current->getID() & bits))))
{
// get world to object space transform
core::matrix4 worldToObject;
if (!current->getAbsoluteTransformation().getInverse(worldToObject))
continue;
// transform vector from world space to object space
core::line3df objectRay(ray);
worldToObject.transformVect(objectRay.start);
worldToObject.transformVect(objectRay.end);
const core::aabbox3df & objectBox = current->getBoundingBox();
// Do the initial intersection test in object space, since the
// object space box test is more accurate.
if (objectBox.isPointInside(objectRay.start))
{
// use fast bbox intersection to find distance to hitpoint
// algorithm from Kay et al., code from gamedev.net
const core::vector3df dir = (objectRay.end - objectRay.start).normalize();
const core::vector3df minDist = (objectBox.MinEdge - objectRay.start) / dir;
const core::vector3df maxDist = (objectBox.MaxEdge - objectRay.start) / dir;
const core::vector3df realMin(core::min_(minDist.X, maxDist.X), core::min_(minDist.Y, maxDist.Y), core::min_(minDist.Z, maxDist.Z));
const core::vector3df realMax(core::max_(minDist.X, maxDist.X), core::max_(minDist.Y, maxDist.Y), core::max_(minDist.Z, maxDist.Z));
const f32 minmax = core::min_(realMax.X, realMax.Y, realMax.Z);
// nearest distance to intersection
const f32 maxmin = core::max_(realMin.X, realMin.Y, realMin.Z);
const f32 toIntersectionSq = (maxmin>0 ? maxmin*maxmin : minmax*minmax);
if (toIntersectionSq < outbestdistance)
{
outbestdistance = toIntersectionSq;
outbestnode = current;
// And we can truncate the ray to stop us hitting further nodes.
ray.end = ray.start + (rayVector * sqrtf(toIntersectionSq));
}
}
else
if (objectBox.intersectsWithLine(objectRay))
{
// Now transform into world space, since we need to use world space
// scales and distances.
core::aabbox3df worldBox(objectBox);
current->getAbsoluteTransformation().transformBox(worldBox);
core::vector3df edges[8];
worldBox.getEdges(edges);
/* We need to check against each of 6 faces, composed of these corners:
/3--------/7
/ | / |
/ | / |
1---------5 |
| 2- - -| -6
| / | /
|/ | /
0---------4/
Note that we define them as opposite pairs of faces.
*/
static const s32 faceEdges[6][3] =
{
{ 0, 1, 5 }, // Front
{ 6, 7, 3 }, // Back
{ 2, 3, 1 }, // Left
{ 4, 5, 7 }, // Right
{ 1, 3, 7 }, // Top
{ 2, 0, 4 } // Bottom
};
core::vector3df intersection;
core::plane3df facePlane;
f32 bestDistToBoxBorder = FLT_MAX;
f32 bestToIntersectionSq = FLT_MAX;
for (s32 face = 0; face < 6; ++face)
{
facePlane.setPlane(edges[faceEdges[face][0]],
edges[faceEdges[face][1]],
edges[faceEdges[face][2]]);
// Only consider lines that might be entering through this face, since we
// already know that the start point is outside the box.
if (facePlane.classifyPointRelation(ray.start) != core::ISREL3D_FRONT)
continue;
// Don't bother using a limited ray, since we already know that it should be long
// enough to intersect with the box.
if (facePlane.getIntersectionWithLine(ray.start, rayVector, intersection))
{
const f32 toIntersectionSq = ray.start.getDistanceFromSQ(intersection);
if (toIntersectionSq < outbestdistance)
{
// We have to check that the intersection with this plane is actually
// on the box, so need to go back to object space again.
worldToObject.transformVect(intersection);
// find the closest point on the box borders. Have to do this as exact checks will fail due to floating point problems.
f32 distToBorder = core::max_(core::min_(core::abs_(objectBox.MinEdge.X - intersection.X), core::abs_(objectBox.MaxEdge.X - intersection.X)),
core::min_(core::abs_(objectBox.MinEdge.Y - intersection.Y), core::abs_(objectBox.MaxEdge.Y - intersection.Y)),
core::min_(core::abs_(objectBox.MinEdge.Z - intersection.Z), core::abs_(objectBox.MaxEdge.Z - intersection.Z)));
if (distToBorder < bestDistToBoxBorder)
{
bestDistToBoxBorder = distToBorder;
bestToIntersectionSq = toIntersectionSq;
}
}
}
// If the ray could be entering through the first face of a pair, then it can't
// also be entering through the opposite face, and so we can skip that face.
if (!(face & 0x01))
++face;
}
if (bestDistToBoxBorder < FLT_MAX)
{
outbestdistance = bestToIntersectionSq;
outbestnode = current;
// If we got a hit, we can now truncate the ray to stop us hitting further nodes.
ray.end = ray.start + (rayVector * sqrtf(outbestdistance));
}
}
}
// Only check the children if this node is visible.
getPickedNodeBB(objecttype, current, ray, bits, noDebugObjects, outbestdistance, outbestnode);
}
}
}
Re: set a type to a SceneNode?
The scenenode id is actually used by the Irrlicht collision functions (I'd prefer if we had an own there, but that did grow historically).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm