123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 |
- // Copyright (C) 2008-2012 Colin MacDonald
- // No rights reserved: this software is in the public domain.
- #include "testUtils.h"
- using namespace irr;
- using namespace core;
- using namespace scene;
- using namespace video;
- static bool testGetCollisionResultPosition(IrrlichtDevice * device,
- ISceneManager * smgr,
- ISceneCollisionManager * collMgr)
- {
- IMeshSceneNode * cubeNode = smgr->addCubeSceneNode(10.f);
- ITriangleSelector * cubeSelector = smgr->createTriangleSelectorFromBoundingBox(cubeNode);
- triangle3df triOut;
- vector3df hitPosition;
- bool falling;
- ISceneNode* hitNode;
- vector3df resultPosition =
- collMgr->getCollisionResultPosition(cubeSelector,
- vector3df(0, 50, 0),
- vector3df(10, 20, 10),
- vector3df(0, -100, 0),
- triOut,
- hitPosition,
- falling,
- hitNode);
- bool result = true;
- if(hitNode != cubeNode)
- {
- logTestString("Unexpected collision node\n");
- result = false;
- }
- if(!equals(resultPosition.Y, 25.f, 0.01f))
- {
- logTestString("Unexpected collision response position\n");
- result = false;
- }
- if(!equals(hitPosition.Y, 5.f, 0.01f))
- {
- logTestString("Unexpected collision position\n");
- result = false;
- }
- resultPosition =
- collMgr->getCollisionResultPosition(cubeSelector,
- vector3df(-20, 0, 0),
- vector3df(10, 20, 10),
- vector3df(100, 0, 0),
- triOut,
- hitPosition,
- falling,
- hitNode);
- if(hitNode != cubeNode)
- {
- logTestString("Unexpected collision node\n");
- result = false;
- }
- if(!equals(resultPosition.X, -15.f, 0.01f))
- {
- logTestString("Unexpected collision response position\n");
- result = false;
- }
- if(!equals(hitPosition.X, -5.f, 0.01f))
- {
- logTestString("Unexpected collision position\n");
- result = false;
- }
- assert_log(result);
- cubeSelector->drop();
- smgr->clear();
- return result;
- }
- // Test that getCollisionPoint() actually uses the closest point, not the closest triangle.
- static bool getCollisionPoint_ignoreTriangleVertices(IrrlichtDevice * device,
- ISceneManager * smgr,
- ISceneCollisionManager * collMgr)
- {
- // Create a cube with a Z face at 5, but corners close to 0
- ISceneNode * farSmallCube = smgr->addCubeSceneNode(10, 0, -1, vector3df(0, 0, 10));
- // Create a cube with a Z face at 0, but corners far from 0
- ISceneNode * nearBigCube = smgr->addCubeSceneNode(100, 0, -1, vector3df(0, 0, 50));
- IMetaTriangleSelector * meta = smgr->createMetaTriangleSelector();
- ITriangleSelector * selector = smgr->createTriangleSelectorFromBoundingBox(farSmallCube);
- meta->addTriangleSelector(selector);
- selector->drop();
- // We should expect a hit on this cube
- selector = smgr->createTriangleSelectorFromBoundingBox(nearBigCube);
- meta->addTriangleSelector(selector);
- selector->drop();
- line3df ray(0, 0, -5, 0, 0, 100);
- vector3df hitPosition;
- triangle3df hitTriangle;
- ISceneNode* hitNode;
- bool collision = collMgr->getCollisionPoint(ray, meta, hitPosition, hitTriangle, hitNode);
- meta->drop();
- if(hitNode != nearBigCube)
- {
- logTestString("getCollisionPoint_ignoreTriangleVertices: hit the wrong node.\n");
- return false;
- }
- if(!collision)
- {
- logTestString("getCollisionPoint_ignoreTriangleVertices: didn't get a hit.\n");
- return false;
- }
- if(hitPosition != vector3df(0, 0, 0))
- {
- logTestString("getCollisionPoint_ignoreTriangleVertices: unexpected hit position %f %f %f.\n",
- hitPosition.X, hitPosition.Y, hitPosition.Z );
- return false;
- }
- smgr->clear();
- return true;
- }
- static bool testGetSceneNodeFromScreenCoordinatesBB(IrrlichtDevice * device,
- ISceneManager * smgr,
- ISceneCollisionManager * collMgr)
- {
- // Create 3 nodes. The nearest node actually contains the camera.
- IMeshSceneNode * cubeNode1 = smgr->addCubeSceneNode(10.f, 0, -1, vector3df(0, 0, 4));
- IMeshSceneNode * cubeNode2 = smgr->addCubeSceneNode(10.f, 0, -1, vector3df(0, 0, 30));
- cubeNode2->setRotation(vector3df(90.f, 90.f, 90.f)); // Just check that rotation doesn't stop us hitting it.
- IMeshSceneNode * cubeNode3 = smgr->addCubeSceneNode(10.f, 0, -1, vector3df(0, 0, 40));
- cubeNode3->setRotation(vector3df(180.f, 180.f, 180.f)); // Just check that rotation doesn't stop us hitting it.
- smgr->addCameraSceneNode();
- device->run();
- smgr->drawAll(); // Get the camera in a good state
- ISceneNode * hitNode = collMgr->getSceneNodeFromScreenCoordinatesBB(position2d<s32>(80, 60));
- // Expect the first node to be hit, since we're starting the check from inside it.
- bool result = true;
- if(hitNode != cubeNode1)
- {
- logTestString("Unexpected node hit. Expected cubeNode1.\n");
- result = false;
- }
- // Now make cubeNode1 invisible and check that cubeNode2 is hit.
- cubeNode1->setVisible(false);
- hitNode = collMgr->getSceneNodeFromScreenCoordinatesBB(position2d<s32>(80, 60));
- if(hitNode != cubeNode2)
- {
- logTestString("Unexpected node hit. Expected cubeNode2.\n");
- result = false;
- }
- // Make cubeNode1 the parent of cubeNode2.
- cubeNode2->setParent(cubeNode1);
- // Check visibility.
- bool visible = cubeNode2->isVisible();
- if(!visible)
- {
- logTestString("cubeNode2 should think that it (in isolation) is visible.\n");
- result = false;
- }
- visible = cubeNode2->isTrulyVisible();
- if(visible)
- {
- logTestString("cubeNode2 should know that it (recursively) is invisible.\n");
- result = false;
- }
- // cubeNode2 should now be an invalid target as well, and so the final cube node should be hit.
- hitNode = collMgr->getSceneNodeFromScreenCoordinatesBB(position2d<s32>(80, 60));
- if(hitNode != cubeNode3)
- {
- logTestString("Unexpected node hit. Expected cubeNode3.\n");
- result = false;
- }
- // Now verify bitmasking
- // Test the 01010101010101010101010101010101 bitmask (0x55555555)
- cubeNode1->setVisible(true);
- cubeNode1->setID(0xAAAAAAAA);
- hitNode = collMgr->getSceneNodeFromScreenCoordinatesBB(position2d<s32>(80, 60), 0x55555555);
- if(hitNode != cubeNode2)
- {
- logTestString("Unexpected node hit. Expected cubeNode2.\n");
- result = false;
- }
- assert_log(result);
- smgr->clear();
- return result;
- }
- static bool getScaledPickedNodeBB(IrrlichtDevice * device,
- ISceneManager * smgr,
- ISceneCollisionManager * collMgr)
- {
- ISceneNode* farTarget = smgr->addCubeSceneNode(1.f);
- farTarget->setScale(vector3df(100.f, 100.f, 10.f));
- farTarget->setPosition(vector3df(0.f, 0.f, 500.f));
- farTarget->updateAbsolutePosition();
- // Create a node that's slightly further away than the closest node,
- // but thinner. Its furthest corner is closer, but the collision
- // position is further, so it should not be selected.
- ISceneNode* middleTarget = smgr->addCubeSceneNode(10.f);
- middleTarget->setPosition(vector3df(0.f, 0.f, 101.f));
- middleTarget->setScale(vector3df(1.f, 1.f, 0.5f));
- middleTarget->updateAbsolutePosition();
- ISceneNode* nearTarget = smgr->addCubeSceneNode(10.f);
- nearTarget->setPosition(vector3df(0.f, 0.f, 100.f));
- nearTarget->updateAbsolutePosition();
- // We'll rotate this node 90 degrees to show that we can hit its side.
- nearTarget->setRotation(vector3df(0.f, 90.f, 0.f));
- line3df ray(0.f, 0.f, 0.f, 0.f, 0.f, 500.f);
- const ISceneNode * const hit = collMgr->getSceneNodeFromRayBB(ray);
- bool result = (hit == nearTarget);
- if(hit == 0)
- logTestString("getSceneNodeFromRayBB() didn't hit anything.\n");
- else if(hit == farTarget)
- logTestString("getSceneNodeFromRayBB() hit the far (scaled) target.\n");
- else if(hit == middleTarget)
- logTestString("getSceneNodeFromRayBB() hit the middle (scaled) target.\n");
- assert_log(result);
- smgr->clear();
- return result;
- }
- // box intersection according to Kay et al., code from gamedev.net
- static bool IntersectBox(const core::vector3df& origin, const core::vector3df& dir, const core::aabbox3df& box)
- {
- core::vector3df minDist = (box.MinEdge - origin)/dir;
- core::vector3df maxDist = (box.MaxEdge - origin)/dir;
- core::vector3df realMin(core::min_(minDist.X, maxDist.X),core::min_(minDist.Y, maxDist.Y),core::min_(minDist.Z, maxDist.Z));
- core::vector3df realMax(core::max_(minDist.X, maxDist.X),core::max_(minDist.Y, maxDist.Y),core::max_(minDist.Z, maxDist.Z));
- f32 minmax = core::min_(realMax.X, realMax.Y, realMax.Z);
- // nearest distance to intersection
- f32 maxmin = core::max_(realMin.X, realMin.Y, realMin.Z);
- return (maxmin >=0 && minmax >= maxmin);
- }
- static bool checkBBoxIntersection(IrrlichtDevice * device,
- ISceneManager * smgr)
- {
- video::IVideoDriver* driver = device->getVideoDriver();
- // add camera
- scene::ICameraSceneNode* camera = smgr->addCameraSceneNode();
- camera->setPosition(core::vector3df(30, 30, 30));
- camera->setTarget(core::vector3df(8.f, 8.f, 8.f));
- camera->setID(0);
- // add a cube to pick
- scene::ISceneNode* cube = smgr->addCubeSceneNode(30, 0, -1, core::vector3df(0,0,0),core::vector3df(30,40,50));
- bool result=true;
- for (u32 round=0; round<2; ++round)
- {
- driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(100, 50, 50, 100));
- smgr->drawAll();
- driver->endScene();
- core::matrix4 invMat = cube->getAbsoluteTransformation();
- invMat.makeInverse();
- s32 hits=0;
- u32 start = device->getTimer()->getRealTime();
- for (u32 i=10; i<150; ++i)
- {
- for (u32 j=10; j<110; ++j)
- {
- const core::position2di pos(i, j);
- // get the line used for picking
- core::line3df ray = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(pos, camera);
- invMat.transformVect(ray.start);
- invMat.transformVect(ray.end);
- hits += (cube->getBoundingBox().intersectsWithLine(ray)?1:0);
- }
- }
- u32 duration = device->getTimer()->getRealTime()-start;
- logTestString("bbox intersection checks %d hits (of 14000).\n", hits);
- hits = -hits;
- start = device->getTimer()->getRealTime();
- for (u32 i=10; i<150; ++i)
- {
- for (u32 j=10; j<110; ++j)
- {
- const core::position2di pos(i, j);
- // get the line used for picking
- core::line3df ray = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(pos, camera);
- invMat.transformVect(ray.start);
- invMat.transformVect(ray.end);
- hits += (IntersectBox(ray.start, (ray.end-ray.start).normalize(), cube->getBoundingBox())?1:0);
- }
- }
- u32 duration2 = device->getTimer()->getRealTime()-start;
- logTestString("bbox intersection resulted in %d misses at a speed of %d (old) compared to %d (new).\n", abs(hits), duration, duration2);
- if (duration>(duration2*1.2f))
- logTestString("Consider replacement of bbox intersection test.\n");
- result &= (hits==0);
- assert_log(result);
- // second round without any hits, so check opposite direction
- camera->setTarget(core::vector3df(80.f, 80.f, 80.f));
- }
- ISceneNode* node = smgr->addSphereSceneNode(5.f, 16, 0, -1, core::vector3df(0, 0, 1), core::vector3df(), core::vector3df(0.3f, 0.3f, 0.3f));
- cube->remove();
- cube = smgr->addCubeSceneNode(10.f, 0, -1, core::vector3df(0, 6.5f, 1), core::vector3df(), core::vector3df(10, 0.1f, 1.f));
- camera->setPosition(core::vector3df(0, 0, 10));
- camera->setTarget(core::vector3df());
- u32 count=0;
- for (u32 i=0; i<30; ++i)
- {
- driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(100, 50, 50, 100));
- smgr->drawAll();
- driver->endScene();
- count += node->getTransformedBoundingBox().intersectsWithBox(cube->getTransformedBoundingBox())?1:0;
- node->setPosition(node->getPosition()+core::vector3df(.5f,.5f,0));
- if (i==8 && count != 0)
- result=false;
- if (i==17 && count != 9)
- result=false;
- }
- if (count != 9)
- result=false;
- smgr->clear();
- return result;
- }
- static bool compareGetSceneNodeFromRayBBWithBBIntersectsWithLine(IrrlichtDevice * device,
- ISceneManager * smgr,
- ISceneCollisionManager * collMgr)
- {
- video::IVideoDriver* driver = device->getVideoDriver();
- // add camera
- scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
- camera->setPosition(core::vector3df(30, 30, 30));
- camera->setTarget(core::vector3df(-8.f, 8.f, -8.f));
- camera->setID(0);
- // add a dynamic light (this causes weirdness)
- smgr->addLightSceneNode(0, core::vector3df(4, 4, 4), video::SColorf(.2f, .3f, .2f));
- // add a cube to pick
- scene::ISceneNode* cube = smgr->addCubeSceneNode(15);
- driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(100, 50, 50, 100));
- smgr->drawAll();
- driver->endScene();
- core::matrix4 invMat = cube->getAbsoluteTransformation();
- invMat.makeInverse();
- bool result = true;
- for (u32 i=76; i<82; ++i)
- {
- for (u32 j=56; j<64; ++j)
- {
- const core::position2di pos(i, j);
- // get the line used for picking
- core::line3df ray = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(pos, camera);
- // find a selected node
- scene::ISceneNode* pick = smgr->getSceneCollisionManager()->getSceneNodeFromRayBB(ray, 1);
- invMat.transformVect(ray.start);
- invMat.transformVect(ray.end);
- const int a_hit = (pick == cube);
- const int b_hit = cube->getBoundingBox().intersectsWithLine(ray);
- result = (a_hit==b_hit);
- }
- }
- assert_log(result);
- smgr->clear();
- return result;
- }
- /** Test functionality of the sceneCollisionManager */
- bool sceneCollisionManager(void)
- {
- IrrlichtDevice * device = irr::createDevice(video::EDT_NULL, dimension2d<u32>(160, 120));
- assert_log(device);
- if(!device)
- return false;
- ISceneManager * smgr = device->getSceneManager();
- ISceneCollisionManager * collMgr = smgr->getSceneCollisionManager();
- bool result = testGetCollisionResultPosition(device, smgr, collMgr);
- smgr->clear();
- result &= testGetSceneNodeFromScreenCoordinatesBB(device, smgr, collMgr);
- result &= getScaledPickedNodeBB(device, smgr, collMgr);
- result &= getCollisionPoint_ignoreTriangleVertices(device, smgr, collMgr);
- result &= checkBBoxIntersection(device, smgr);
- result &= compareGetSceneNodeFromRayBBWithBBIntersectsWithLine(device, smgr, collMgr);
- device->closeDevice();
- device->run();
- device->drop();
- return result;
- }
|