for me these are some big issues right now, like missing irrlicht-functions for non-symmetrical frustum ( left !=-right etc...), which seem to be missing,
My testing showed that my functions produce the same Projection-Matrices as OpenGL, but Irrlicht does not. They always differ!!!
So i ask, why? What is the goal of this? Is it a BUG?
By the way why is there only a empty SViewFrustum constructor and no memberfunctions for getting the Left,Right,Top,Bottom values
Here my test-code:
Code: Select all
#include <irrlicht.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <cmath>
using namespace irr;
IrrlichtDevice* createDeviceGL();
void printMatrix( const core::matrix4& m, const core::stringc& matName ); // pretty-print irr-matrix
void printMatrix( GLenum mat, const core::stringc& matName ); // pretty-print gl-matrix
void extractClipPlanes( const core::matrix4& projMat ) //, f32& fLeft, f32& fRight, f32& fBottom, f32& fTop, f32& fNear, f32& fFar)
{
f32 fLeft, fRight, fBottom, fTop, fNear, fFar;
//! check if ortho or not
bool isOrtho = true;
if ( core::equals( projMat(3,3), 0.f ) )
isOrtho = false;
if ( core::equals( projMat(3,2), -1.f ) )
isOrtho = false;
if (isOrtho)
{
fNear = (projMat(2,3)+1.f)/projMat(2,2);
fFar = (projMat(2,3)-1.f)/projMat(2,2);
fLeft = -(projMat(0,3)+1.f)/projMat(0,0);
fRight = -(projMat(0,3)-1.f)/projMat(0,0);
fTop = -(projMat(1,3)-1.f)/projMat(1,1);
fBottom = -(projMat(1,3)+1.f)/projMat(1,1);
}
else
{
fNear = projMat(2,3)/(projMat(2,2)-1.f);
fFar = projMat(2,3)/(projMat(2,2)+1.f);
fLeft = fNear*(projMat(0,2)-1.f)/projMat(0,0);
fRight = fNear*(projMat(0,2)+1.f)/projMat(0,0);
fTop = fNear*(projMat(1,2)-1.f)/projMat(1,1);
fBottom = fNear*(projMat(1,2)+1.f)/projMat(1,1);
}
printf("isOrtho=%s, l=%.2f, r=%.2f, b=%.2f, t=%.2f, n=%.2f, f=%.2f\n", isOrtho?"true":"false", fLeft, fRight, fBottom, fTop, fNear, fFar);
}
core::matrix4 myBuildProjectionMatrix( bool isOrtho, f32 fLeft, f32 fRight, f32 fBottom, f32 fTop, f32 fNear, f32 fFar)
{
core::matrix4 m = core::IdentityMatrix;
if (isOrtho)
{ // gluOrtho2d
m(0,0) = 2.f / (fRight - fLeft); // III.
m(1,1) = 2.f / (fTop - fBottom); // V.
m(2,2) = -2.f / (fFar - fNear); // I.
m(3,3) = 1.f;
m(0,3) = -(fRight + fLeft) / (fRight - fLeft); // IV.
m(1,3) = -(fTop + fBottom) / (fTop - fBottom); // VI.
m(2,3) = -(fFar + fNear) / (fFar - fNear); // II.
}
else
{ // glFustum
m(0,0) = 2.f*fNear / (fRight - fLeft); // III.
m(1,1) = 2.f*fNear / (fTop - fBottom); // V.
m(2,2) = -1.f*(fFar + fNear) / (fFar - fNear); // I.
m(3,3) = 0.f;
m(0,2) = (fRight + fLeft) / (fRight - fLeft); // IV.
m(1,2) = (fTop + fBottom) / (fTop - fBottom); // VI.
m(2,3) = -2.f*fNear*fFar / (fFar - fNear); // II.
m(3,2) = -1.f;
}
return m;
}
core::matrix4 myBuildProjectionMatrix( f32 fFOVy, f32 fAspect, f32 fNear, f32 fFar)
{ // gluPerspective
core::matrix4 m = core::IdentityMatrix;
f32 f = 1.0f / tan(0.5f*fFOVy);
m(0,0) = f / fAspect;
m(1,1) = f;
m(2,2) = (fFar + fNear) / (fNear - fFar);
m(3,3) = 0.f;
m(2,3) = 2.f*fFar*fNear / (fNear - fFar);
m(3,2) = -1.f;
return m;
}
s32 main( s32 argc, c8** argv )
{
IrrlichtDevice* device = createDeviceGL();
if (!device)
exit(1);
device->setWindowCaption(L"Irrlicht-Projection-Matrix-Tests");
ILogger* logger = device->getLogger();
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
printf("\n");
//! Test [1] Ortho-Projection
core::matrix4 ortho1 = myBuildProjectionMatrix(true, -5,5,-3,3,-1,1);
core::matrix4 ortho2; ortho2.buildProjectionMatrixOrthoLH(10,6,-1,1);
// core::matrix4 ortho3; ortho3.buildProjectionMatrixOrthoRH(10,6,-1,1);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluOrtho2D(-5,5,-3,3);
printMatrix(ortho1, "myBuildProjectionMatrix(true, -5,5,-3,3,-1,1)");
printMatrix(ortho2, "irrBuildProjectionMatrixOrthoLH(10,6,-1,1)");
// printMatrix(ortho3, "irrBuildProjectionMatrixOrthoRH(10,6,-1,1)");
printMatrix(GL_PROJECTION_MATRIX, "gluOrtho2D(-5,5,-3,3)");
//! Test [2] Perspective-Projection
core::matrix4 frust1 = myBuildProjectionMatrix(false, -5,5,-3,3,1,1000);
core::matrix4 frust2; frust2.buildProjectionMatrixPerspectiveLH(10,6,1,1000);
// core::matrix4 frust3; frust3.buildProjectionMatrixPerspectiveRH(10,6,1,1000);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glFrustum(-5,5,-3,3,1,1000);
printMatrix(frust1, "myBuildProjectionMatrix(false, -5,5,-3,3,1,1000)");
printMatrix(frust2, "irrBuildProjectionMatrixPerspectiveLH(10,6,1,1000)");
// printMatrix(frust3, "irrBuildProjectionMatrixPerspectiveRH(10,6,1,1000)");
printMatrix(GL_PROJECTION_MATRIX, "glFrustum(-5,5,-3,3,1,1000)");
//! Test [3] IrrCamProj vs gluPerspective
f32 FOV = core::PI/2.5f;
f32 ASPECT = (f32)driver->getScreenSize().Width / (f32)driver->getScreenSize().Height;
core::matrix4 persp1 = myBuildProjectionMatrix(FOV,ASPECT,1,1000);
core::matrix4 persp2; persp2.buildProjectionMatrixPerspectiveFovLH(FOV,ASPECT,1,1000);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective(FOV*core::RADTODEG,ASPECT,1,1000);
printMatrix(persp1, "myBuildProjectionMatrix(FOV,ASPECT,1,1000)");
printMatrix(persp2, "irrBuildProjectionMatrixPerspectiveFovLH(FOV,ASPECT,1,1000)");
printMatrix(GL_PROJECTION_MATRIX, "gluPerspective(FOV,ASPECT,1,1000)");
//! Test [4] Non-Symmetrical
core::matrix4 ortho4 = myBuildProjectionMatrix(true, -15,25,-13,3,-1,1);
printMatrix(ortho4, "myBuildProjectionMatrix(true, -15,25,-13,3,-1,1)");
core::matrix4 frust4 = myBuildProjectionMatrix(false, -15,25,-13,3,1,1000);
printMatrix(frust4, "myBuildProjectionMatrix(false, -15,25,-13,3,1,1000)");
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluOrtho2D(-15,25,-13,3);
printMatrix(GL_PROJECTION_MATRIX, "gluOrtho2D(-15,25,-13,3)");
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glFrustum(-15,25,-13,3,1,1000);
printMatrix(GL_PROJECTION_MATRIX, "glFrustum(-15,25,-13,3,1,1000)");
if (device)
device->drop();
return 0;
}
void printMatrix( const core::matrix4& m, const core::stringc& matName )
{
printf("%s:\n", matName.c_str());
for (u32 y=0; y<4; ++y)
{
printf("%f %f %f %f\n", m(y,0), m(y,1), m(y,2), m(y,3));
}
extractClipPlanes( m );
printf("\n");
}
void printMatrix( GLenum mat, const core::stringc& matName )
{
GLfloat tmp[16];
char sz_txt[32];
core::stringc txt("");
glGetFloatv(mat, tmp);
txt = matName; txt+=":\n";
core::matrix4 irrMat;
for (u32 y=0; y<4; ++y)
{
for (u32 x=0; x<4; ++x)
{
memset(sz_txt, 0, sizeof(sz_txt));
sprintf( sz_txt, "%.6f", tmp[y+x*4] );
irrMat(y,x) = tmp[y+4*x];
txt+=sz_txt;
if (x<3)
txt+=", ";
}
txt+="\n";
}
printf("%s", txt.c_str());
extractClipPlanes( irrMat );
printf("\n");
}
IrrlichtDevice* createDeviceGL()
{
IrrlichtDevice* nulldev = createDevice(video::EDT_NULL);
SIrrlichtCreationParameters params;
params.Fullscreen = false;
if (nulldev)
{
params.WindowSize = nulldev->getVideoModeList()->getDesktopResolution() - core::dimension2du(100,100);
params.Bits = nulldev->getVideoModeList()->getDesktopDepth();
if (nulldev->isDriverSupported(video::EDT_OPENGL))
{
params.DriverType = video::EDT_OPENGL;
params.WithAlphaChannel = false;
params.AntiAlias = video::EAAM_ALPHA_TO_COVERAGE;
params.ZBufferBits = 24;
params.Vsync = false;
params.Bits = 32;
params.Doublebuffer = true;
params.HighPrecisionFPU = true;
params.Stencilbuffer = false;
}
nulldev->drop();
}
// create opengl-device
return createDeviceEx(params);
}
i wrote the myBuildProjectionMatrix functions with help of online images showing how the matrices look like
i used this for glFrustum
i used this for gluOrtho
i used this for gluPerpective
my test-results:
2nd Issue:
How do i extract Left,Right,Top,Bottom from a Irrlicht SViewFrustum (not the planes, the single values)?
3rd
How do i construct a SViewFrustum out of Left,Right,Top,Bottom,Near,Far,
4th
The Importance is the creation of non-symmetrical Frustum ( left != -right; top != -bottom )
Pls add some constructors for SViewFrustum, or member-functions for core::matrix to emulate glFrustum functionality!
Thx = f;3,3