- Triangle selectors created from animated mesh scene nodes will update themselves as required to stay in sync with the node. - ISceneCollisionManager::getSceneNodeAndCollisionPointFromRay() allows selection by BB and triangle on a heirarchy of scene nodes. Example 07 updated to show the usage of ISceneCollisionManager::getSceneNodeAndCollisionPointFromRay(), used on animated meshes. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@2177 dfc29bdd-3216-0410-991c-e03cc46cb475master
parent
78f9dee79c
commit
5478f80545
|
@ -463,6 +463,10 @@ Changes in version 1.6, TA
|
||||||
|
|
||||||
Changes in version 1.6
|
Changes in version 1.6
|
||||||
|
|
||||||
|
- ISceneCollisionManager::getSceneNodeAndCollisionPointFromRay() allows selection by BB and triangle on a heirarchy of scene nodes.
|
||||||
|
|
||||||
|
- Triangle selectors created from animated mesh scene nodes will update themselves as required to stay in sync with the node.
|
||||||
|
|
||||||
- IVideoDriver has methods to enumerate the available image loaders and writers.
|
- IVideoDriver has methods to enumerate the available image loaders and writers.
|
||||||
|
|
||||||
- Octtree scene nodes are now IMeshSceneNodes rather than ISceneNodes, and so you can call getMesh() on them.
|
- Octtree scene nodes are now IMeshSceneNodes rather than ISceneNodes, and so you can call getMesh() on them.
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
/** Example 007 Collision
|
/** Example 007 Collision
|
||||||
|
|
||||||
In this tutorial, I will show how to detect collisions with the Irrlicht Engine.
|
We will describe 2 methods: Automatic collision detection for moving through 3d worlds
|
||||||
I will describe 3 methods: Automatic collision detection for moving through 3d
|
with stair climbing and sliding, and manual scene node and triangle picking using a
|
||||||
worlds with stair climbing and sliding, manual triangle picking, and manual
|
ray. In this case, we will use a ray coming out from the camera, but you can use
|
||||||
scene node picking.
|
any ray.
|
||||||
|
|
||||||
To start, we take the program from tutorial 2, which loads and displays a quake
|
To start, we take the program from tutorial 2, which loads and displays a quake
|
||||||
3 level. We will use the level to walk in it and to pick triangles from it. In
|
3 level. We will use the level to walk in it and to pick triangles from. In
|
||||||
addition we'll place 3 animated models into it for scene node picking. The
|
addition we'll place 3 animated models into it for triangle picking. The
|
||||||
following code starts up the engine and loads a quake 3 level. I will not
|
following code starts up the engine and loads a quake 3 level, as per tutorial 2.
|
||||||
explain it, because it should already be known from tutorial 2.
|
|
||||||
*/
|
*/
|
||||||
#include <irrlicht.h>
|
#include <irrlicht.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -20,6 +19,22 @@ using namespace irr;
|
||||||
#pragma comment(lib, "Irrlicht.lib")
|
#pragma comment(lib, "Irrlicht.lib")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
// I use this ISceneNode ID to indicate a scene node that is
|
||||||
|
// not pickable by getSceneNodeAndCollisionPointFromRay()
|
||||||
|
ID_IsNotPickable = 0,
|
||||||
|
|
||||||
|
// I use this flag in ISceneNode IDs to indicate that the
|
||||||
|
// scene node can be picked by ray selection.
|
||||||
|
IDFlag_IsPickable = 1 << 0,
|
||||||
|
|
||||||
|
// I use this flag in ISceneNode IDs to indicate that the
|
||||||
|
// scene node can be highlighted. In this example, the
|
||||||
|
// homonids can be highlighted, but the level mesh can't.
|
||||||
|
IDFlag_IsHighlightable = 1 << 1
|
||||||
|
};
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
// let user select driver type
|
// let user select driver type
|
||||||
|
@ -61,10 +76,9 @@ int main()
|
||||||
scene::IAnimatedMesh* q3levelmesh = smgr->getMesh("20kdm2.bsp");
|
scene::IAnimatedMesh* q3levelmesh = smgr->getMesh("20kdm2.bsp");
|
||||||
scene::IMeshSceneNode* q3node = 0;
|
scene::IMeshSceneNode* q3node = 0;
|
||||||
|
|
||||||
|
// The Quake mesh is pickable, but doesn't get highlighted.
|
||||||
if (q3levelmesh)
|
if (q3levelmesh)
|
||||||
q3node = smgr->addOctTreeSceneNode(q3levelmesh->getMesh(0));
|
q3node = smgr->addOctTreeSceneNode(q3levelmesh->getMesh(0), 0, IDFlag_IsPickable);
|
||||||
|
|
||||||
q3node->setID(0); // Make it an invalid target for bounding box collision
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
So far so good, we've loaded the quake 3 level like in tutorial 2. Now,
|
So far so good, we've loaded the quake 3 level like in tutorial 2. Now,
|
||||||
|
@ -90,11 +104,12 @@ int main()
|
||||||
selector = smgr->createOctTreeTriangleSelector(
|
selector = smgr->createOctTreeTriangleSelector(
|
||||||
q3node->getMesh(), q3node, 128);
|
q3node->getMesh(), q3node, 128);
|
||||||
q3node->setTriangleSelector(selector);
|
q3node->setTriangleSelector(selector);
|
||||||
|
// We're not done with this selector yet, so don't drop it.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We add a first person shooter camera to the scene for being able to
|
We add a first person shooter camera to the scene so that we can see and
|
||||||
move in the quake 3 level like in tutorial 2. But this, time, we add a
|
move in the quake 3 level like in tutorial 2. But this, time, we add a
|
||||||
special animator to the camera: A Collision Response animator. This
|
special animator to the camera: A Collision Response animator. This
|
||||||
animator modifies the scene node to which it is attached to in order to
|
animator modifies the scene node to which it is attached to in order to
|
||||||
|
@ -102,12 +117,12 @@ int main()
|
||||||
only thing we have to tell the animator is how the world looks like,
|
only thing we have to tell the animator is how the world looks like,
|
||||||
how big the scene node is, how much gravity to apply and so on. After the
|
how big the scene node is, how much gravity to apply and so on. After the
|
||||||
collision response animator is attached to the camera, we do not have to do
|
collision response animator is attached to the camera, we do not have to do
|
||||||
anything more for collision detection, anything is done automatically,
|
anything more for collision detection, anything is done automatically.
|
||||||
all other collision detection code below is for picking. And please
|
The rest of the collision detection code below is for picking. And please
|
||||||
note another cool feature: The collision response animator can be
|
note another cool feature: The collision response animator can be
|
||||||
attached also to all other scene nodes, not only to cameras. And it can
|
attached also to all other scene nodes, not only to cameras. And it can
|
||||||
be mixed with other scene node animators. In this way, collision
|
be mixed with other scene node animators. In this way, collision
|
||||||
detection and response in the Irrlicht engine is really, really easy.
|
detection and response in the Irrlicht engine is really easy.
|
||||||
|
|
||||||
Now we'll take a closer look on the parameters of
|
Now we'll take a closer look on the parameters of
|
||||||
createCollisionResponseAnimator(). The first parameter is the
|
createCollisionResponseAnimator(). The first parameter is the
|
||||||
|
@ -132,9 +147,8 @@ int main()
|
||||||
// Set a jump speed of 3 units per second, which gives a fairly realistic jump
|
// Set a jump speed of 3 units per second, which gives a fairly realistic jump
|
||||||
// when used with the gravity of (0, -10, 0) in the collision response animator.
|
// when used with the gravity of (0, -10, 0) in the collision response animator.
|
||||||
scene::ICameraSceneNode* camera =
|
scene::ICameraSceneNode* camera =
|
||||||
smgr->addCameraSceneNodeFPS(0, 100.0f, .3f, -1, 0, 0, true, 3.f);
|
smgr->addCameraSceneNodeFPS(0, 100.0f, .3f, ID_IsNotPickable, 0, 0, true, 3.f);
|
||||||
camera->setPosition(core::vector3df(-100,50,-150));
|
camera->setPosition(core::vector3df(-100,50,-150));
|
||||||
camera->setID(0); // Make it an invalid target for bounding box collision
|
|
||||||
|
|
||||||
if (selector)
|
if (selector)
|
||||||
{
|
{
|
||||||
|
@ -142,165 +156,154 @@ int main()
|
||||||
selector, camera, core::vector3df(30,50,30),
|
selector, camera, core::vector3df(30,50,30),
|
||||||
core::vector3df(0,-10,0),
|
core::vector3df(0,-10,0),
|
||||||
core::vector3df(0,50,0));
|
core::vector3df(0,50,0));
|
||||||
|
selector->drop(); // As soon as we're done with the selector, drop it.
|
||||||
camera->addAnimator(anim);
|
camera->addAnimator(anim);
|
||||||
anim->drop();
|
anim->drop(); // And likewise, drop the animator when we're done referring to it.
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Now I create three animated characters which we can pick, a dynamic light for
|
||||||
Because collision detection is no big deal in irrlicht, I'll describe how to
|
// lighting them, and a billboard for drawing where we found an intersection.
|
||||||
do two different types of picking in the next section. But before this,
|
|
||||||
I'll prepare the scene a little. I need three animated characters which we
|
|
||||||
could pick later, a dynamic light for lighting them,
|
|
||||||
a billboard for drawing where we found an intersection, and, yes, I need to
|
|
||||||
get rid of this mouse cursor. :)
|
|
||||||
*/
|
|
||||||
|
|
||||||
// disable mouse cursor
|
|
||||||
|
|
||||||
|
// First, let's get rid of the mouse cursor. We'll use a billboard to show
|
||||||
|
// what we're looking at.
|
||||||
device->getCursorControl()->setVisible(false);
|
device->getCursorControl()->setVisible(false);
|
||||||
|
|
||||||
// add billboard
|
// Add the billboard.
|
||||||
|
|
||||||
scene::IBillboardSceneNode * bill = smgr->addBillboardSceneNode();
|
scene::IBillboardSceneNode * bill = smgr->addBillboardSceneNode();
|
||||||
bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR );
|
bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR );
|
||||||
bill->setMaterialTexture(0, driver->getTexture("../../media/particle.bmp"));
|
bill->setMaterialTexture(0, driver->getTexture("../../media/particle.bmp"));
|
||||||
bill->setMaterialFlag(video::EMF_LIGHTING, false);
|
bill->setMaterialFlag(video::EMF_LIGHTING, false);
|
||||||
bill->setMaterialFlag(video::EMF_ZBUFFER, false);
|
bill->setMaterialFlag(video::EMF_ZBUFFER, false);
|
||||||
bill->setSize(core::dimension2d<f32>(20.0f, 20.0f));
|
bill->setSize(core::dimension2d<f32>(20.0f, 20.0f));
|
||||||
bill->setID(0); // Make it an invalid target for bounding box collision
|
bill->setID(ID_IsNotPickable); // This ensures that we don't accidentally ray-pick it
|
||||||
|
|
||||||
// add 3 animated faeries. We'll make their bounding boxes visible so
|
// Add 3 animated hominids, which we can pick using a ray-triangle intersection.
|
||||||
// that we can see the same boxes that the scene collision manager is
|
// They all animate quite slowly, to make it easier to see that accurate triangle
|
||||||
// using to perform the getSceneNodeFromCameraBB() check below.
|
// selection is being performed.
|
||||||
|
scene::IAnimatedMeshSceneNode* node = 0;
|
||||||
|
|
||||||
|
// Add an MD2 node, which uses vertex-based animation.
|
||||||
|
node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/faerie.md2"),
|
||||||
|
0,
|
||||||
|
IDFlag_IsPickable | IDFlag_IsHighlightable);
|
||||||
|
node->setPosition(core::vector3df(-70,-25,-120)); // Put its feet on the floor.
|
||||||
|
node->setScale(core::vector3df(2, 2, 2)); // Make it appear realistically scaled
|
||||||
|
node->setMD2Animation(scene::EMAT_RUN);
|
||||||
|
node->setAnimationSpeed(20.f);
|
||||||
video::SMaterial material;
|
video::SMaterial material;
|
||||||
material.setTexture(0, driver->getTexture("../../media/faerie2.bmp"));
|
material.setTexture(0, driver->getTexture("../../media/faerie2.bmp"));
|
||||||
material.Lighting = true;
|
material.Lighting = true;
|
||||||
|
|
||||||
scene::IAnimatedMeshSceneNode* node = 0;
|
|
||||||
scene::IAnimatedMesh* faerie = smgr->getMesh("../../media/faerie.md2");
|
|
||||||
|
|
||||||
if (faerie)
|
|
||||||
{
|
|
||||||
node = smgr->addAnimatedMeshSceneNode(faerie);
|
|
||||||
node->setPosition(core::vector3df(-70,0,-90));
|
|
||||||
node->setMD2Animation(scene::EMAT_RUN);
|
|
||||||
node->getMaterial(0) = material;
|
node->getMaterial(0) = material;
|
||||||
node->setDebugDataVisible(scene::EDS_BBOX_ALL);
|
|
||||||
|
|
||||||
node = smgr->addAnimatedMeshSceneNode(faerie);
|
// Now create a triangle selector for it. The selector will know that it
|
||||||
node->setPosition(core::vector3df(-70,0,-30));
|
// is associated with an animated node, and will update itself as necessary.
|
||||||
node->setMD2Animation(scene::EMAT_SALUTE);
|
selector = smgr->createTriangleSelector(node);
|
||||||
node->getMaterial(0) = material;
|
node->setTriangleSelector(selector);
|
||||||
node->setDebugDataVisible(scene::EDS_BBOX_ALL);
|
selector->drop(); // We're done with this selector, so drop it now.
|
||||||
|
|
||||||
node = smgr->addAnimatedMeshSceneNode(faerie);
|
// This X files uses skeletal animation, but without skinning.
|
||||||
node->setPosition(core::vector3df(-70,0,-60));
|
node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/dwarf.x"),
|
||||||
node->setMD2Animation(scene::EMAT_JUMP);
|
0,
|
||||||
node->getMaterial(0) = material;
|
IDFlag_IsPickable | IDFlag_IsHighlightable);
|
||||||
node->setDebugDataVisible(scene::EDS_BBOX_ALL);
|
node->setPosition(core::vector3df(-70,-66,0)); // Put its feet on the floor.
|
||||||
}
|
node->setRotation(core::vector3df(0,-90,0)); // And turn it towards the camera.
|
||||||
|
node->setAnimationSpeed(20.f);
|
||||||
|
selector = smgr->createTriangleSelector(node);
|
||||||
|
node->setTriangleSelector(selector);
|
||||||
|
selector->drop();
|
||||||
|
|
||||||
|
// And this B3D file uses skinned skeletal animation.
|
||||||
|
node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/ninja.b3d"),
|
||||||
|
0,
|
||||||
|
IDFlag_IsPickable | IDFlag_IsHighlightable);
|
||||||
|
node->setScale(core::vector3df(10, 10, 10));
|
||||||
|
node->setPosition(core::vector3df(-70,-66,-60));
|
||||||
|
node->setRotation(core::vector3df(0,90,0));
|
||||||
|
node->setAnimationSpeed(10.f);
|
||||||
|
// Just do the same as we did above.
|
||||||
|
selector = smgr->createTriangleSelector(node);
|
||||||
|
node->setTriangleSelector(selector);
|
||||||
|
selector->drop();
|
||||||
|
|
||||||
material.setTexture(0, 0);
|
material.setTexture(0, 0);
|
||||||
material.Lighting = false;
|
material.Lighting = false;
|
||||||
|
|
||||||
// Add a light
|
// Add a light, so that the unselected nodes aren't completely dark.
|
||||||
|
|
||||||
scene::ILightSceneNode * light = smgr->addLightSceneNode(0, core::vector3df(-60,100,400),
|
scene::ILightSceneNode * light = smgr->addLightSceneNode(0, core::vector3df(-60,100,400),
|
||||||
video::SColorf(1.0f,1.0f,1.0f,1.0f),
|
video::SColorf(1.0f,1.0f,1.0f,1.0f),
|
||||||
600.0f);
|
600.0f);
|
||||||
light->setID(0); // Make it an invalid target for bounding box collision
|
light->setID(ID_IsNotPickable); // Make it an invalid target for selection.
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
For not making it to complicated, I'm doing picking inside the drawing
|
|
||||||
loop. We take two pointers for storing the current and the last
|
|
||||||
selected scene node and start the loop.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
scene::ISceneNode* selectedSceneNode = 0;
|
|
||||||
scene::ISceneNode* lastSelectedSceneNode = 0;
|
|
||||||
|
|
||||||
|
|
||||||
|
// Remember which scene node is highlighted
|
||||||
|
scene::ISceneNode* highlightedSceneNode = 0;
|
||||||
|
scene::ISceneCollisionManager* collMan = smgr->getSceneCollisionManager();
|
||||||
int lastFPS = -1;
|
int lastFPS = -1;
|
||||||
|
|
||||||
while(device->run())
|
while(device->run())
|
||||||
if (device->isWindowActive())
|
if (device->isWindowActive())
|
||||||
{
|
{
|
||||||
driver->beginScene(true, true, 0);
|
driver->beginScene(true, true, 0);
|
||||||
|
|
||||||
smgr->drawAll();
|
smgr->drawAll();
|
||||||
|
|
||||||
/*
|
// Unlight any currently highlighted scene node
|
||||||
After we've drawn the whole scene with smgr->drawAll(), we'll
|
if (highlightedSceneNode)
|
||||||
do the first picking: We want to know which triangle of the
|
{
|
||||||
world we are looking at. In addition, we want the exact point
|
highlightedSceneNode->setMaterialFlag(video::EMF_LIGHTING, true);
|
||||||
of the quake 3 level we are looking at. For this, we create a
|
highlightedSceneNode = 0;
|
||||||
3d line starting at the position of the camera and going
|
}
|
||||||
through the lookAt-target of it. Then we ask the collision
|
|
||||||
manager if this line collides with a triangle of the world
|
|
||||||
stored in the triangle selector. If yes, we draw the 3d
|
|
||||||
triangle and set the position of the billboard to the
|
|
||||||
intersection point.
|
|
||||||
*/
|
|
||||||
|
|
||||||
core::line3d<f32> line;
|
// All intersections in this example are done with a ray cast out from the camera to
|
||||||
line.start = camera->getPosition();
|
// a distance of 1000. You can easily modify this to check (e.g.) a bullet
|
||||||
line.end = line.start + (camera->getTarget() - line.start).normalize() * 1000.0f;
|
// trajectory or a sword's position, or create a ray from a mouse click position using
|
||||||
|
// ISceneCollisionManager::getRayFromScreenCoordinates()
|
||||||
|
core::line3d<f32> ray;
|
||||||
|
ray.start = camera->getPosition();
|
||||||
|
ray.end = ray.start + (camera->getTarget() - ray.start).normalize() * 1000.0f;
|
||||||
|
|
||||||
|
// Tracks the current intersection point with the level or a mesh
|
||||||
core::vector3df intersection;
|
core::vector3df intersection;
|
||||||
core::triangle3df tri;
|
// Used to show with triangle has been hit
|
||||||
const scene::ISceneNode* hitNode;
|
core::triangle3df hitTriangle;
|
||||||
|
|
||||||
if (smgr->getSceneCollisionManager()->getCollisionPoint(
|
// This call is all you need to perform ray/triangle collision on every scene node
|
||||||
line, selector, intersection, tri, hitNode))
|
// that has a triangle selector, including the Quake level mesh. It finds the nearest
|
||||||
|
// collision point/triangle, and returns the scene node containing that point.
|
||||||
|
// Irrlicht provides other types of selection, including ray/triangle selector,
|
||||||
|
// ray/box and ellipse/triangle selector, plus associated helpers.
|
||||||
|
// See the methods of ISceneCollisionManager
|
||||||
|
scene::ISceneNode * selectedSceneNode = collMan->getSceneNodeAndCollisionPointFromRay(
|
||||||
|
ray,
|
||||||
|
intersection, // This will be the position of the collision
|
||||||
|
hitTriangle, // This will be the triangle hit in the collision
|
||||||
|
IDFlag_IsPickable, // This ensures that only nodes that we have
|
||||||
|
// set up to be pickable are considered
|
||||||
|
0 // Check the entire scene (this is actually the implicit default)
|
||||||
|
);
|
||||||
|
|
||||||
|
// If the ray hit anything, move the billboard to the collision position and draw
|
||||||
|
// the triangle that was hit.
|
||||||
|
if(selectedSceneNode)
|
||||||
{
|
{
|
||||||
bill->setPosition(intersection);
|
bill->setPosition(intersection);
|
||||||
|
|
||||||
|
// We need to reset the transform before doing our own rendering.
|
||||||
driver->setTransform(video::ETS_WORLD, core::matrix4());
|
driver->setTransform(video::ETS_WORLD, core::matrix4());
|
||||||
driver->setMaterial(material);
|
driver->setMaterial(material);
|
||||||
driver->draw3DTriangle(tri, video::SColor(0,255,0,0));
|
driver->draw3DTriangle(hitTriangle, video::SColor(0,255,0,0));
|
||||||
|
|
||||||
|
// We can check the flags for the scene node that was hit to see if it should be
|
||||||
|
// highlighted. The animated nodes can be highlighted, but not the Quake level mesh
|
||||||
|
if((selectedSceneNode->getID() & IDFlag_IsHighlightable) == IDFlag_IsHighlightable)
|
||||||
|
{
|
||||||
|
highlightedSceneNode = selectedSceneNode;
|
||||||
|
|
||||||
|
// Highlighting in this case means turning lighting OFF for this node,
|
||||||
|
// which means that it will be drawn with full brightness.
|
||||||
|
highlightedSceneNode->setMaterialFlag(video::EMF_LIGHTING, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We're all done drawing, so end the scene.
|
||||||
/*
|
|
||||||
Another type of picking supported by the Irrlicht Engine is
|
|
||||||
scene node picking based on bounding boxes. Every scene node has
|
|
||||||
got a bounding box, and because of that, it's very fast for
|
|
||||||
example to get the scene node which the camera looks at. Again,
|
|
||||||
we ask the collision manager for this, and if we've got a scene
|
|
||||||
node, we highlight it by disabling Lighting in its material, if
|
|
||||||
it is not the billboard or the quake 3 level.
|
|
||||||
We use a collision bitmask of 1, i.e. any scene node with a scene ID
|
|
||||||
with bit 1 set is valid for collision. Scene nodes ID defaults to 0xFFFFFFFF
|
|
||||||
so all nodes will have this bit by default. We have called setID(0) on
|
|
||||||
the nodes that we don't care about in order to clear this bit and make
|
|
||||||
them invalid targets for collision. This makes the test a bit more
|
|
||||||
efficient, and also stops us from accidentally picking unexpected nodes,
|
|
||||||
e.g. the quake3 level, camera, light and billboard nodes. By default,
|
|
||||||
these *are* valid targets for bounding box selection.
|
|
||||||
*/
|
|
||||||
|
|
||||||
selectedSceneNode =
|
|
||||||
smgr->getSceneCollisionManager()->getSceneNodeFromCameraBB(camera, 1);
|
|
||||||
|
|
||||||
if (lastSelectedSceneNode)
|
|
||||||
lastSelectedSceneNode->setMaterialFlag(video::EMF_LIGHTING, true);
|
|
||||||
|
|
||||||
if (selectedSceneNode == q3node || selectedSceneNode == bill)
|
|
||||||
selectedSceneNode = 0;
|
|
||||||
|
|
||||||
if (selectedSceneNode)
|
|
||||||
selectedSceneNode->setMaterialFlag(video::EMF_LIGHTING, false);
|
|
||||||
|
|
||||||
lastSelectedSceneNode = selectedSceneNode;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
That's it, we just have to finish drawing.
|
|
||||||
*/
|
|
||||||
|
|
||||||
driver->endScene();
|
driver->endScene();
|
||||||
|
|
||||||
int fps = driver->getFPS();
|
int fps = driver->getFPS();
|
||||||
|
@ -317,7 +320,6 @@ int main()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selector->drop();
|
|
||||||
device->drop();
|
device->drop();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -121,29 +121,29 @@ namespace scene
|
||||||
virtual ISceneNode* getSceneNodeFromScreenCoordinatesBB(const core::position2d<s32> & pos,
|
virtual ISceneNode* getSceneNodeFromScreenCoordinatesBB(const core::position2d<s32> & pos,
|
||||||
s32 idBitMask=0, bool bNoDebugObjects = false) = 0;
|
s32 idBitMask=0, bool bNoDebugObjects = false) = 0;
|
||||||
|
|
||||||
//! Get the nearest scene node which collides with a 3d ray and whose id matches a bitmask.
|
//! Returns the nearest scene node which collides with a 3d ray and whose id matches a bitmask.
|
||||||
/** The collision tests are done using a bounding box for each
|
/** The collision tests are done using a bounding box for each scene node.
|
||||||
scene node.
|
|
||||||
\param ray: Line with witch collisions are tested.
|
\param ray: Line with witch collisions are tested.
|
||||||
\param idBitMask: Only scene nodes with an id with bits set
|
\param idBitMask: Only scene nodes with an id which matches at least one of the
|
||||||
like in this mask will be tested. If the BitMask is 0, this
|
bits contained in this mask will be tested. However, if this parameter is 0, then
|
||||||
feature is disabled.
|
all nodes are checked.
|
||||||
\param bNoDebugObjects: Doesn't take debug objects into account
|
\param bNoDebugObjects: Doesn't take debug objects into account when true. These
|
||||||
when true. These are scene nodes with IsDebugObject() = true.
|
are scene nodes with IsDebugObject() = true.
|
||||||
\return Scene node nearest to ray.start, which collides with
|
\return Returns the scene node nearest to ray.start, which collides with the
|
||||||
the ray and matches the idBitMask, if the mask is not null. If
|
ray and matches the idBitMask, if the mask is not null. If no scene
|
||||||
no scene node is found, 0 is returned. */
|
node is found, 0 is returned. */
|
||||||
virtual ISceneNode* getSceneNodeFromRayBB(const core::line3d<f32> & ray,
|
virtual ISceneNode* getSceneNodeFromRayBB(const core::line3d<f32> ray,
|
||||||
s32 idBitMask=0, bool bNoDebugObjects = false) = 0;
|
s32 idBitMask=0, bool bNoDebugObjects = false) = 0;
|
||||||
|
|
||||||
//! Get the scene node, which the overgiven camera is looking at and whose id matches the bitmask.
|
//! Get the scene node, which the given camera is looking at and whose id matches the bitmask.
|
||||||
/** A ray is simply casted from the position of the camera to
|
/** A ray is simply casted from the position of the camera to
|
||||||
the view target position, and all scene nodes are tested
|
the view target position, and all scene nodes are tested
|
||||||
against this ray. The collision tests are done using a bounding
|
against this ray. The collision tests are done using a bounding
|
||||||
box for each scene node.
|
box for each scene node.
|
||||||
\param camera: Camera from which the ray is casted.
|
\param camera: Camera from which the ray is casted.
|
||||||
\param idBitMask: Only scene nodes with an id with bits set
|
\param idBitMask: Only scene nodes with an id which matches at least one of the
|
||||||
like in this mask will be tested. If the BitMask is 0, this
|
bits contained in this mask will be tested. However, if this parameter is 0, then
|
||||||
|
all nodes are checked.
|
||||||
feature is disabled.
|
feature is disabled.
|
||||||
\param bNoDebugObjects: Doesn't take debug objects into account
|
\param bNoDebugObjects: Doesn't take debug objects into account
|
||||||
when true. These are scene nodes with IsDebugObject() = true.
|
when true. These are scene nodes with IsDebugObject() = true.
|
||||||
|
@ -152,6 +152,41 @@ namespace scene
|
||||||
no scene node is found, 0 is returned. */
|
no scene node is found, 0 is returned. */
|
||||||
virtual ISceneNode* getSceneNodeFromCameraBB(ICameraSceneNode* camera,
|
virtual ISceneNode* getSceneNodeFromCameraBB(ICameraSceneNode* camera,
|
||||||
s32 idBitMask=0, bool bNoDebugObjects = false) = 0;
|
s32 idBitMask=0, bool bNoDebugObjects = false) = 0;
|
||||||
|
|
||||||
|
//! Perform a ray/box and ray/triangle collision check on a heirarchy of scene nodes.
|
||||||
|
/** This checks all scene nodes under the specified one, first by ray/bounding
|
||||||
|
box, and then by accurate ray/triangle collision, finding the nearest collision,
|
||||||
|
and the scene node containg it. It returns the node hit, and (via output
|
||||||
|
parameters) the position of the collision, and the triangle that was hit.
|
||||||
|
|
||||||
|
All scene nodes in the hierarchy tree under the specified node are checked. Only
|
||||||
|
notes that are visible, with an ID that matches at least one bit in the supplied
|
||||||
|
bitmask, and which have a triangle selector are considered as candidates for being hit.
|
||||||
|
You do not have to build a meta triangle selector; the individual triangle selectors
|
||||||
|
of each candidate scene node are used automatically.
|
||||||
|
|
||||||
|
\param ray: Line with which collisions are tested.
|
||||||
|
\param outCollisionPoint: If a collision is detected, this will contain the
|
||||||
|
position of the nearest collision.
|
||||||
|
\param outTriangle: If a collision is detected, this will contain the triangle
|
||||||
|
with which the ray collided.
|
||||||
|
\param idBitMask: Only scene nodes with an id which matches at least one of the
|
||||||
|
bits contained in this mask will be tested. However, if this parameter is 0, then
|
||||||
|
all nodes are checked.
|
||||||
|
\param collisionRootNode: the scene node at which to begin checking. Only this
|
||||||
|
node and its children will be checked. If you want to check the entire scene,
|
||||||
|
pass 0, and the root scene node will be used (this is the default).
|
||||||
|
\param noDebugObjects: when true, debug objects are not considered viable targets.
|
||||||
|
Debug objects are scene nodes with IsDebugObject() = true.
|
||||||
|
\return Returns the scene node containing the hit triangle nearest to ray.start.
|
||||||
|
If no collision is detected, then 0 is returned. */
|
||||||
|
virtual ISceneNode* getSceneNodeAndCollisionPointFromRay(
|
||||||
|
core::line3df ray,
|
||||||
|
core::vector3df & outCollisionPoint,
|
||||||
|
core::triangle3df & outTriangle,
|
||||||
|
s32 idBitMask = 0,
|
||||||
|
ISceneNode * collisionRootNode = 0,
|
||||||
|
bool noDebugObjects = false) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1170,6 +1170,14 @@ namespace scene
|
||||||
See IReferenceCounted::drop() for more information. */
|
See IReferenceCounted::drop() for more information. */
|
||||||
virtual ITriangleSelector* createTriangleSelector(IMesh* mesh, ISceneNode* node) = 0;
|
virtual ITriangleSelector* createTriangleSelector(IMesh* mesh, ISceneNode* node) = 0;
|
||||||
|
|
||||||
|
//! Creates a simple ITriangleSelector, based on an animated mesh scene node.
|
||||||
|
//! Details of the mesh associated with the node will be extracted internally.
|
||||||
|
//! Call ITriangleSelector::update() to have the triangle selector updated based
|
||||||
|
//! on the current frame of the animated mesh scene node.
|
||||||
|
//! \param: The animated mesh scene node from which to build the selector
|
||||||
|
virtual ITriangleSelector* createTriangleSelector(IAnimatedMeshSceneNode* node) = 0;
|
||||||
|
|
||||||
|
|
||||||
//! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box.
|
//! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box.
|
||||||
/** Triangle selectors
|
/** Triangle selectors
|
||||||
can be used for doing collision detection. Every time when triangles are
|
can be used for doing collision detection. Every time when triangles are
|
||||||
|
|
|
@ -57,7 +57,7 @@ ISceneNode* CSceneCollisionManager::getSceneNodeFromScreenCoordinatesBB(
|
||||||
|
|
||||||
//! Returns the nearest scene node which collides with a 3d ray and
|
//! Returns the nearest scene node which collides with a 3d ray and
|
||||||
//! which id matches a bitmask.
|
//! which id matches a bitmask.
|
||||||
ISceneNode* CSceneCollisionManager::getSceneNodeFromRayBB(const core::line3d<f32> & ray,
|
ISceneNode* CSceneCollisionManager::getSceneNodeFromRayBB(const core::line3d<f32> ray,
|
||||||
s32 idBitMask,
|
s32 idBitMask,
|
||||||
bool bNoDebugObjects)
|
bool bNoDebugObjects)
|
||||||
{
|
{
|
||||||
|
@ -214,6 +214,122 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ISceneNode* CSceneCollisionManager::getSceneNodeAndCollisionPointFromRay(
|
||||||
|
core::line3df ray,
|
||||||
|
core::vector3df & outCollisionPoint,
|
||||||
|
core::triangle3df & outTriangle,
|
||||||
|
s32 idBitMask,
|
||||||
|
ISceneNode * collisionRootNode,
|
||||||
|
bool noDebugObjects)
|
||||||
|
{
|
||||||
|
ISceneNode* bestNode = 0;
|
||||||
|
f32 bestDistanceSquared = FLT_MAX;
|
||||||
|
|
||||||
|
if(0 == collisionRootNode)
|
||||||
|
collisionRootNode = SceneManager->getRootSceneNode();
|
||||||
|
|
||||||
|
// We don't try to do anything too clever, like sorting the candidate
|
||||||
|
// nodes by distance to bounding-box. In the example below, we could do the
|
||||||
|
// triangle collision check with node A first, but we'd have to check node B
|
||||||
|
// anyway, as the actual collision point could be (and is) closer than the
|
||||||
|
// collision point in node A.
|
||||||
|
//
|
||||||
|
// ray end
|
||||||
|
// |
|
||||||
|
// AAAAAAAAAA
|
||||||
|
// A |
|
||||||
|
// A | B
|
||||||
|
// A | B
|
||||||
|
// A BBBBB
|
||||||
|
// A |
|
||||||
|
// A |
|
||||||
|
// |
|
||||||
|
// |
|
||||||
|
// ray start
|
||||||
|
//
|
||||||
|
// We therefore have to do a full BB and triangle collision on every scene
|
||||||
|
// node in order to find the nearest collision point, so sorting them by
|
||||||
|
// bounding box would be pointless.
|
||||||
|
|
||||||
|
getPickedNodeFromBBAndSelector(collisionRootNode,
|
||||||
|
ray,
|
||||||
|
idBitMask,
|
||||||
|
noDebugObjects,
|
||||||
|
bestDistanceSquared,
|
||||||
|
bestNode,
|
||||||
|
outCollisionPoint,
|
||||||
|
outTriangle);
|
||||||
|
return bestNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CSceneCollisionManager::getPickedNodeFromBBAndSelector(
|
||||||
|
ISceneNode * root,
|
||||||
|
const core::line3df & ray,
|
||||||
|
s32 bits,
|
||||||
|
bool noDebugObjects,
|
||||||
|
f32 & outBestDistanceSquared,
|
||||||
|
ISceneNode * & outBestNode,
|
||||||
|
core::vector3df & outBestCollisionPoint,
|
||||||
|
core::triangle3df & outBestTriangle)
|
||||||
|
{
|
||||||
|
const core::list<ISceneNode*>& children = root->getChildren();
|
||||||
|
|
||||||
|
core::list<ISceneNode*>::ConstIterator it = children.begin();
|
||||||
|
for (; it != children.end(); ++it)
|
||||||
|
{
|
||||||
|
ISceneNode* current = *it;
|
||||||
|
ITriangleSelector * selector = current->getTriangleSelector();
|
||||||
|
|
||||||
|
if (selector && current->isVisible() &&
|
||||||
|
(noDebugObjects ? !current->isDebugObject() : true) &&
|
||||||
|
(bits==0 || (bits != 0 && (current->getID() & bits))))
|
||||||
|
{
|
||||||
|
// get world to object space transform
|
||||||
|
core::matrix4 mat;
|
||||||
|
if (!current->getAbsoluteTransformation().getInverse(mat))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// transform vector from world space to object space
|
||||||
|
core::line3df line(ray);
|
||||||
|
mat.transformVect(line.start);
|
||||||
|
mat.transformVect(line.end);
|
||||||
|
|
||||||
|
const core::aabbox3df& box = current->getBoundingBox();
|
||||||
|
|
||||||
|
core::vector3df candidateCollisionPoint;
|
||||||
|
core::triangle3df candidateTriangle;
|
||||||
|
|
||||||
|
// do intersection test in object space
|
||||||
|
const ISceneNode * hitNode = 0;
|
||||||
|
if (box.intersectsWithLine(line)
|
||||||
|
&&
|
||||||
|
getCollisionPoint(ray, selector, candidateCollisionPoint, candidateTriangle, hitNode))
|
||||||
|
{
|
||||||
|
const f32 distanceSquared = (candidateCollisionPoint - ray.start).getLengthSQ();
|
||||||
|
|
||||||
|
if(distanceSquared < outBestDistanceSquared)
|
||||||
|
{
|
||||||
|
outBestDistanceSquared = distanceSquared;
|
||||||
|
outBestNode = current;
|
||||||
|
outBestCollisionPoint = candidateCollisionPoint;
|
||||||
|
outBestTriangle = candidateTriangle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getPickedNodeFromBBAndSelector(current,
|
||||||
|
ray,
|
||||||
|
bits,
|
||||||
|
noDebugObjects,
|
||||||
|
outBestDistanceSquared,
|
||||||
|
outBestNode,
|
||||||
|
outBestCollisionPoint,
|
||||||
|
outBestTriangle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//! Returns the scene node, at which the overgiven camera is looking at and
|
//! Returns the scene node, at which the overgiven camera is looking at and
|
||||||
//! which id matches the bitmask.
|
//! which id matches the bitmask.
|
||||||
|
|
|
@ -32,9 +32,8 @@ namespace scene
|
||||||
|
|
||||||
//! Returns the nearest scene node which collides with a 3d ray and
|
//! Returns the nearest scene node which collides with a 3d ray and
|
||||||
//! which id matches a bitmask.
|
//! which id matches a bitmask.
|
||||||
virtual ISceneNode* getSceneNodeFromRayBB(const core::line3d<f32> & ray,
|
virtual ISceneNode* getSceneNodeFromRayBB(const core::line3d<f32> ray,
|
||||||
s32 idBitMask=0,
|
s32 idBitMask=0, bool bNoDebugObjects = false);
|
||||||
bool bNoDebugObjects = false);
|
|
||||||
|
|
||||||
//! Returns the scene node, at which the overgiven camera is looking at and
|
//! Returns the scene node, at which the overgiven camera is looking at and
|
||||||
//! which id matches the bitmask.
|
//! which id matches the bitmask.
|
||||||
|
@ -69,6 +68,17 @@ namespace scene
|
||||||
virtual core::position2d<s32> getScreenCoordinatesFrom3DPosition(
|
virtual core::position2d<s32> getScreenCoordinatesFrom3DPosition(
|
||||||
const core::vector3df & pos, ICameraSceneNode* camera=0);
|
const core::vector3df & pos, ICameraSceneNode* camera=0);
|
||||||
|
|
||||||
|
//! Gets the scene node and nearest collision point for a ray based on
|
||||||
|
//! the nodes' id bitmasks, bounding boxes and triangle selectors.
|
||||||
|
virtual ISceneNode* getSceneNodeAndCollisionPointFromRay(
|
||||||
|
core::line3df ray,
|
||||||
|
core::vector3df & outCollisionPoint,
|
||||||
|
core::triangle3df & outTriangle,
|
||||||
|
s32 idBitMask = 0,
|
||||||
|
ISceneNode * collisionRootNode = 0,
|
||||||
|
bool noDebugObjects = false);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
//! recursive method for going through all scene nodes
|
//! recursive method for going through all scene nodes
|
||||||
|
@ -79,6 +89,17 @@ namespace scene
|
||||||
f32& outbestdistance,
|
f32& outbestdistance,
|
||||||
ISceneNode*& outbestnode);
|
ISceneNode*& outbestnode);
|
||||||
|
|
||||||
|
//! recursive method for going through all scene nodes
|
||||||
|
void getPickedNodeFromBBAndSelector(ISceneNode * root,
|
||||||
|
const core::line3df & ray,
|
||||||
|
s32 bits,
|
||||||
|
bool noDebugObjects,
|
||||||
|
f32 & outBestDistanceSquared,
|
||||||
|
ISceneNode * & outBestNode,
|
||||||
|
core::vector3df & outBestCollisionPoint,
|
||||||
|
core::triangle3df & outBestTriangle);
|
||||||
|
|
||||||
|
|
||||||
struct SCollisionData
|
struct SCollisionData
|
||||||
{
|
{
|
||||||
core::vector3df eRadius;
|
core::vector3df eRadius;
|
||||||
|
|
|
@ -1662,6 +1662,16 @@ ITriangleSelector* CSceneManager::createTriangleSelector(IMesh* mesh, ISceneNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! Creates a simple and updatable ITriangleSelector, based on a the mesh owned by an
|
||||||
|
//! animated scene node
|
||||||
|
ITriangleSelector* CSceneManager::createTriangleSelector(IAnimatedMeshSceneNode* node)
|
||||||
|
{
|
||||||
|
if(!node || !node->getMesh())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return new CTriangleSelector(node);
|
||||||
|
}
|
||||||
|
|
||||||
//! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box.
|
//! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box.
|
||||||
ITriangleSelector* CSceneManager::createTriangleSelectorFromBoundingBox(ISceneNode* node)
|
ITriangleSelector* CSceneManager::createTriangleSelectorFromBoundingBox(ISceneNode* node)
|
||||||
{
|
{
|
||||||
|
|
|
@ -327,6 +327,13 @@ namespace scene
|
||||||
//! Creates a simple ITriangleSelector, based on a mesh.
|
//! Creates a simple ITriangleSelector, based on a mesh.
|
||||||
virtual ITriangleSelector* createTriangleSelector(IMesh* mesh, ISceneNode* node);
|
virtual ITriangleSelector* createTriangleSelector(IMesh* mesh, ISceneNode* node);
|
||||||
|
|
||||||
|
//! Creates a simple ITriangleSelector, based on an animated mesh scene node.
|
||||||
|
//! Details of the mesh associated with the node will be extracted internally.
|
||||||
|
//! Call ITriangleSelector::update() to have the triangle selector updated based
|
||||||
|
//! on the current frame of the animated mesh scene node.
|
||||||
|
//! \param: The animated mesh scene node from which to build the selector
|
||||||
|
virtual ITriangleSelector* createTriangleSelector(IAnimatedMeshSceneNode* node);
|
||||||
|
|
||||||
//! Creates a simple ITriangleSelector, based on a mesh.
|
//! Creates a simple ITriangleSelector, based on a mesh.
|
||||||
virtual ITriangleSelector* createOctTreeTriangleSelector(IMesh* mesh,
|
virtual ITriangleSelector* createOctTreeTriangleSelector(IMesh* mesh,
|
||||||
ISceneNode* node, s32 minimalPolysPerNode);
|
ISceneNode* node, s32 minimalPolysPerNode);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "CTriangleSelector.h"
|
#include "CTriangleSelector.h"
|
||||||
#include "ISceneNode.h"
|
#include "ISceneNode.h"
|
||||||
#include "IMeshBuffer.h"
|
#include "IMeshBuffer.h"
|
||||||
|
#include "IAnimatedMeshSceneNode.h"
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
|
@ -13,7 +14,7 @@ namespace scene
|
||||||
|
|
||||||
//! constructor
|
//! constructor
|
||||||
CTriangleSelector::CTriangleSelector(const ISceneNode* node)
|
CTriangleSelector::CTriangleSelector(const ISceneNode* node)
|
||||||
: SceneNode(node)
|
: SceneNode(node), AnimatedNode(0)
|
||||||
{
|
{
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
setDebugName("CTriangleSelector");
|
setDebugName("CTriangleSelector");
|
||||||
|
@ -23,12 +24,37 @@ CTriangleSelector::CTriangleSelector(const ISceneNode* node)
|
||||||
|
|
||||||
//! constructor
|
//! constructor
|
||||||
CTriangleSelector::CTriangleSelector(const IMesh* mesh, const ISceneNode* node)
|
CTriangleSelector::CTriangleSelector(const IMesh* mesh, const ISceneNode* node)
|
||||||
: SceneNode(node)
|
: SceneNode(node), AnimatedNode(0)
|
||||||
{
|
{
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
setDebugName("CTriangleSelector");
|
setDebugName("CTriangleSelector");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
createFromMesh(mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
CTriangleSelector::CTriangleSelector(IAnimatedMeshSceneNode* node)
|
||||||
|
: SceneNode(reinterpret_cast<ISceneNode*>(node)), AnimatedNode(node)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
setDebugName("CTriangleSelector");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(!AnimatedNode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
IAnimatedMesh * animatedMesh = AnimatedNode->getMesh();
|
||||||
|
if(!animatedMesh)
|
||||||
|
return;
|
||||||
|
|
||||||
|
IMesh * mesh = animatedMesh->getMesh((s32)AnimatedNode->getFrameNr());
|
||||||
|
|
||||||
|
if(mesh)
|
||||||
|
createFromMesh(mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTriangleSelector::createFromMesh(const IMesh * mesh)
|
||||||
|
{
|
||||||
const u32 cnt = mesh->getMeshBufferCount();
|
const u32 cnt = mesh->getMeshBufferCount();
|
||||||
u32 totalFaceCount = 0;
|
u32 totalFaceCount = 0;
|
||||||
for (u32 j=0; j<cnt; ++j)
|
for (u32 j=0; j<cnt; ++j)
|
||||||
|
@ -53,6 +79,62 @@ CTriangleSelector::CTriangleSelector(const IMesh* mesh, const ISceneNode* node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CTriangleSelector::updateFromMesh(const IMesh* mesh) const
|
||||||
|
{
|
||||||
|
if(!mesh)
|
||||||
|
return;
|
||||||
|
|
||||||
|
u32 meshBuffers = mesh->getMeshBufferCount();
|
||||||
|
u32 triangleCount = 0;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < meshBuffers; ++i)
|
||||||
|
{
|
||||||
|
IMeshBuffer* buf = mesh->getMeshBuffer(i);
|
||||||
|
u32 idxCnt = buf->getIndexCount();
|
||||||
|
const u16* indices = buf->getIndices();
|
||||||
|
|
||||||
|
switch (buf->getVertexType())
|
||||||
|
{
|
||||||
|
case video::EVT_STANDARD:
|
||||||
|
{
|
||||||
|
video::S3DVertex* vtx = (video::S3DVertex*)buf->getVertices();
|
||||||
|
for (u32 index = 0; index < idxCnt; index += 3)
|
||||||
|
{
|
||||||
|
core::triangle3df & tri = Triangles[triangleCount++];
|
||||||
|
tri.pointA = vtx[indices[index + 0]].Pos;
|
||||||
|
tri.pointB = vtx[indices[index + 1]].Pos;
|
||||||
|
tri.pointC = vtx[indices[index + 2]].Pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case video::EVT_2TCOORDS:
|
||||||
|
{
|
||||||
|
video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buf->getVertices();
|
||||||
|
for (u32 index = 0; index < idxCnt; index += 3)
|
||||||
|
{
|
||||||
|
core::triangle3df & tri = Triangles[triangleCount++];
|
||||||
|
tri.pointA = vtx[indices[index + 0]].Pos;
|
||||||
|
tri.pointB = vtx[indices[index + 1]].Pos;
|
||||||
|
tri.pointC = vtx[indices[index + 2]].Pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case video::EVT_TANGENTS:
|
||||||
|
{
|
||||||
|
video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buf->getVertices();
|
||||||
|
for (u32 index = 0; index < idxCnt; index += 3)
|
||||||
|
{
|
||||||
|
core::triangle3df & tri = Triangles[triangleCount++];
|
||||||
|
tri.pointA = vtx[indices[index + 0]].Pos;
|
||||||
|
tri.pointB = vtx[indices[index + 1]].Pos;
|
||||||
|
tri.pointC = vtx[indices[index + 2]].Pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//! constructor
|
//! constructor
|
||||||
CTriangleSelector::CTriangleSelector(const core::aabbox3d<f32>& box, const ISceneNode* node)
|
CTriangleSelector::CTriangleSelector(const core::aabbox3d<f32>& box, const ISceneNode* node)
|
||||||
|
@ -66,11 +148,36 @@ CTriangleSelector::CTriangleSelector(const core::aabbox3d<f32>& box, const IScen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CTriangleSelector::update(void) const
|
||||||
|
{
|
||||||
|
if(!AnimatedNode)
|
||||||
|
return; //< harmless no-op
|
||||||
|
|
||||||
|
s32 currentFrame = (s32)AnimatedNode->getFrameNr();
|
||||||
|
if(currentFrame == LastMeshFrame)
|
||||||
|
return; //< Nothing to do
|
||||||
|
|
||||||
|
LastMeshFrame = currentFrame;
|
||||||
|
IAnimatedMesh * animatedMesh = AnimatedNode->getMesh();
|
||||||
|
|
||||||
|
if(animatedMesh)
|
||||||
|
{
|
||||||
|
IMesh * mesh = animatedMesh->getMesh(LastMeshFrame);
|
||||||
|
|
||||||
|
if(mesh)
|
||||||
|
updateFromMesh(mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//! Gets all triangles.
|
//! Gets all triangles.
|
||||||
void CTriangleSelector::getTriangles(core::triangle3df* triangles,
|
void CTriangleSelector::getTriangles(core::triangle3df* triangles,
|
||||||
s32 arraySize, s32& outTriangleCount,
|
s32 arraySize, s32& outTriangleCount,
|
||||||
const core::matrix4* transform) const
|
const core::matrix4* transform) const
|
||||||
{
|
{
|
||||||
|
// Update my triangles if necessary
|
||||||
|
update();
|
||||||
|
|
||||||
s32 cnt = Triangles.size();
|
s32 cnt = Triangles.size();
|
||||||
if (cnt > arraySize)
|
if (cnt > arraySize)
|
||||||
cnt = arraySize;
|
cnt = arraySize;
|
||||||
|
@ -85,12 +192,6 @@ void CTriangleSelector::getTriangles(core::triangle3df* triangles,
|
||||||
|
|
||||||
for (s32 i=0; i<cnt; ++i)
|
for (s32 i=0; i<cnt; ++i)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
triangles[i] = Triangles[i];
|
|
||||||
mat.transformVect(triangles[i].pointA);
|
|
||||||
mat.transformVect(triangles[i].pointB);
|
|
||||||
mat.transformVect(triangles[i].pointC);
|
|
||||||
*/
|
|
||||||
mat.transformVect( triangles[i].pointA, Triangles[i].pointA );
|
mat.transformVect( triangles[i].pointA, Triangles[i].pointA );
|
||||||
mat.transformVect( triangles[i].pointB, Triangles[i].pointB );
|
mat.transformVect( triangles[i].pointB, Triangles[i].pointB );
|
||||||
mat.transformVect( triangles[i].pointC, Triangles[i].pointC );
|
mat.transformVect( triangles[i].pointC, Triangles[i].pointC );
|
||||||
|
|
|
@ -15,6 +15,7 @@ namespace scene
|
||||||
{
|
{
|
||||||
|
|
||||||
class ISceneNode;
|
class ISceneNode;
|
||||||
|
class IAnimatedMeshSceneNode;
|
||||||
|
|
||||||
//! Stupid triangle selector without optimization
|
//! Stupid triangle selector without optimization
|
||||||
class CTriangleSelector : public ITriangleSelector
|
class CTriangleSelector : public ITriangleSelector
|
||||||
|
@ -27,6 +28,10 @@ public:
|
||||||
//! Constructs a selector based on a mesh
|
//! Constructs a selector based on a mesh
|
||||||
CTriangleSelector(const IMesh* mesh, const ISceneNode* node);
|
CTriangleSelector(const IMesh* mesh, const ISceneNode* node);
|
||||||
|
|
||||||
|
//! Constructs a selector based on an animated mesh scene node
|
||||||
|
//!\param node An animated mesh scene node, which must have a valid mesh
|
||||||
|
CTriangleSelector(IAnimatedMeshSceneNode* node);
|
||||||
|
|
||||||
//! Constructs a selector based on a bounding box
|
//! Constructs a selector based on a bounding box
|
||||||
CTriangleSelector(const core::aabbox3d<f32>& box, const ISceneNode* node);
|
CTriangleSelector(const core::aabbox3d<f32>& box, const ISceneNode* node);
|
||||||
|
|
||||||
|
@ -50,9 +55,22 @@ public:
|
||||||
virtual const ISceneNode* getSceneNodeForTriangle(u32 triangleIndex) const { return SceneNode; }
|
virtual const ISceneNode* getSceneNodeForTriangle(u32 triangleIndex) const { return SceneNode; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
//! Create from a mesh
|
||||||
|
virtual void createFromMesh(const IMesh* mesh);
|
||||||
|
|
||||||
|
//! Update when the mesh has changed
|
||||||
|
virtual void updateFromMesh(const IMesh* mesh) const;
|
||||||
|
|
||||||
|
//! Update the triangle selector, which will only have an effect if it
|
||||||
|
//! was built from an animated mesh and that mesh's frame has changed
|
||||||
|
//! since the last time it was updated.
|
||||||
|
virtual void update(void) const;
|
||||||
|
|
||||||
const ISceneNode* SceneNode;
|
const ISceneNode* SceneNode;
|
||||||
mutable core::array<core::triangle3df> Triangles;
|
mutable core::array<core::triangle3df> Triangles;
|
||||||
|
|
||||||
|
IAnimatedMeshSceneNode* AnimatedNode;
|
||||||
|
mutable s32 LastMeshFrame;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace scene
|
} // end namespace scene
|
||||||
|
|
Loading…
Reference in New Issue