Bon, j'ai donc pris le temps ce soir de re-coder ma fonction DM3D qui était basée sur du code DX9c pour pouvoir tourner avec
Irrlicht. Cela semble bien fonctionner, je vais l'éprouver pour pouvoir l'intégrer dans mon moteur de terrain.
Le code se décompose en 4 parties:
1- une petite classe
Plane, pour me faciliter les choses, quelques lignes pas bien sorcier.
2- UpdateCullInfo: partie qui permet d'établir les 6 plans du cube de polygone de vue.
3- _isVisible: fonction d'interogation pour savoir si un mesh (ou plutot son boundingBox) est visible ou non.
4- corps du programme de test (identique au code ci-dessus du message initial.
Voilà, voici donc le code complet, fonctions et corps de test.
#include <irrlicht.h>
#include <iostream>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#endif
// données globales
bool _bExit = false;
ISceneManager* scenegraph;
//-----------------------------------------------------------------------------
// Name: Plane class
// Desc: petite classe plane personnalisée pour pour ce codage.
//-----------------------------------------------------------------------------
class Plane
{
public:
float a;
float b;
float c;
float d;
Plane(): a(0),b(0),c(0),d(0) {}
Plane(float aa, float bb, float cc, float dd): a(aa), b(bb), c(cc), d(dd){}
Plane operator-(const Plane& other) const { return Plane(a - other.a, b - other.b, c - other.c, d - other.d); }
Plane operator+(const Plane& other) const { return Plane(a + other.a, b + other.b, c + other.c, d + other.d); }
float operator[](unsigned i) const { switch(i) {case 0: return a; case 1: return b; case 2: return c; case 3: return d;default: return 0; } }
void Normalize() { float m; m = sqrt( a*a + b*b + c*c + d*d ); a = a / m; b = b / m; c = c/ m; d = d /m; }
float DotCoord(float *V) { return (a * V[0] + b * V[1] + c * V[2] + d); }
};
// donnée globale, ou autre en fonction des besoins
Plane mFrustumPlane[6];
//-----------------------------------------------------------------------------
// Name: UpdateCullInfo()
// Desc: Update Cull Info, attention avec la camera courante
//-----------------------------------------------------------------------------
void UpdateCullInfo()
{
scene::ICameraSceneNode* cam = scenegraph->getActiveCamera();
core::matrix4 pMatProj, pMatView;
pMatProj = cam->getProjectionMatrix();
pMatView = cam->getViewMatrix();
core::matrix4 VPI = pMatProj * pMatView;
Plane col0(VPI(0,0), VPI(1,0), VPI(2,0), VPI(3,0));
Plane col1(VPI(0,1), VPI(1,1), VPI(2,1), VPI(3,1));
Plane col2(VPI(0,2), VPI(1,2), VPI(2,2), VPI(3,2));
Plane col3(VPI(0,3), VPI(1,3), VPI(2,3), VPI(3,3));
// construit les 6 plane du Frustum view
mFrustumPlane[0] = col2; // near
mFrustumPlane[1] = (col3 - col2); // far
mFrustumPlane[2] = (col3 + col0); // left
mFrustumPlane[3] = (col3 - col0); // right
mFrustumPlane[4] = (col3 - col1); // top
mFrustumPlane[5] = (col3 + col1); // bottom
for(int i = 0; i < 6; i++)
{
mFrustumPlane[i].Normalize();
}
}
//-----------------------------------------------------------------------------
// Name: _isVisible()
// Desc: test de visibilité d'un mesh
//-----------------------------------------------------------------------------
int _isVisible(const core::aabbox3d<f32>& box)
{
float P[3];
float Q[3];
// la classe vector3d ne possédant pas d'opérateur de surcharge []....
float Min[3]; memcpy( Min, &box.MinEdge.X, sizeof(float)*3);
float Max[3]; memcpy( Max, &box.MaxEdge.X, sizeof(float)*3);
for(int i = 0; i < 6; ++i)
{
// pour chaque coordonnées x, y, z...
for(int j = 0; j < 3; ++j)
{
// etabli le poiont PQ dans la même direction que le plan normal sur l'axe.
if( mFrustumPlane[i][j] >= 0.0f )
{
P[j] = Min[j];
Q[j] = Max[j];
}
else
{
P[j] = Max[j];
Q[j] = Min[j];
}
}
if( mFrustumPlane[i].DotCoord(Q) < 0.0f ) // en dehor, exit procedure
return false;
}
return true;
}
int main()
{
// choix driver
video::E_DRIVER_TYPE driverType;
printf("Please select the driver you want for this example:\
"\\
" (a) Direct3D 9.0c\
(b) Direct3D 8.1\
(c) OpenGL 1.5\
"\\
" (d) Software Renderer\
(e) Burning's Software Renderer\
"\\
" (f) NullDevice\
(otherKey) exit\
\
");
char i;
std::cin >> i;
switch(i)
{
case 'a': driverType = video::EDT_DIRECT3D9;break;
case 'b': driverType = video::EDT_DIRECT3D8;break;
case 'c': driverType = video::EDT_OPENGL; break;
case 'd': driverType = video::EDT_SOFTWARE; break;
case 'e': driverType = video::EDT_BURNINGSVIDEO;break;
case 'f': driverType = video::EDT_NULL; break;
default: return 0;
}
IrrlichtDevice *device = createDevice( driverType,
dimension2d<s32>(640, 480),
32,
false,
false,
true,
NULL);
IVideoDriver* driver = device->getVideoDriver();
scenegraph = device->getSceneManager();
// cube 1
ISceneNode* cube1 = scenegraph->addCubeSceneNode(2.0f, scenegraph->getRootSceneNode());
cube1->setPosition( vector3df(10,0,0) );
// définition camera.
SKeyMap keyMap[4] =
{
{EKA_MOVE_FORWARD, KEY_UP},
{EKA_MOVE_BACKWARD, KEY_DOWN},
{EKA_STRAFE_LEFT, KEY_LEFT},
{EKA_STRAFE_RIGHT, KEY_RIGHT},
};
ICameraSceneNode* cam = scenegraph->addCameraSceneNodeFPS( scenegraph->getRootSceneNode() , 100.0f, 50.0f, -1, keyMap, 4);
cam->setPosition(core::vector3df(0,1,-10));
// boucle principale
int lastFPS = -1;
while(device->run() & !_bExit)
{
driver->beginScene(true, true, SColor(255,100,101,140));
scenegraph->drawAll();
driver->endScene();
//============================
// mise a jour frustum
//============================
UpdateCullInfo();
//============================
// frustum test
//============================
// récupération du boundingBox, puis transformation pour faire le test
core::aabbox3d<f32> box = cube1->getBoundingBox();
core::matrix4 matMesh = cube1->getAbsoluteTransformation();
matMesh.transformBoxEx(box);
int FrustumCode = _isVisible(box);
// des information temps réél
int fps = driver->getFPS();
core::stringw str = L"Test visibilité: ";
str += FrustumCode;
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
device->drop();
return 0;
}