[unconfirmed] Messed up Projection-Matrices

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
gerdb
Posts: 194
Joined: Wed Dec 02, 2009 8:21 pm
Location: Dresden, Germany

[unconfirmed] Messed up Projection-Matrices

Post by gerdb »

hi, im currently investigating some issues with irrlicht's creation of projection matrices

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
Image

i used this for gluOrtho
Image

i used this for gluPerpective
Image

my test-results:

Image

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
Last edited by gerdb on Wed Aug 08, 2012 9:29 pm, edited 1 time in total.
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: [BUG] Messed up Projection-Matrices

Post by hendu »

As a workaround, isn't there a setProjectionMatrix method on cameras? I think you can create a matrix elsewhere and just upload it.
gerdb
Posts: 194
Joined: Wed Dec 02, 2009 8:21 pm
Location: Dresden, Germany

Re: [BUG] Messed up Projection-Matrices

Post by gerdb »

thx hendu,
scene::ICameraSceneNode::setProjectionMatrix
that should work for what i like to do.

Does this update the internal SViewFrustum correctly for non-symmetrical-frustum?

I still need to extract the Left,Right,Top,Bottom Values out of the Projection-Matrix, do you have any hints for that?

As i understand i first have to determine if the ProjMat is Ortho or not and then try to solve some equations to extract these params from cells.

EDIT: i solved the equations with VirtualTi89 and got this, seems to work, even for unsymmetrical frustum, but irrlicht fails here too.

Code: Select all

 
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);
}
 
output: All fails are irrlicht related!

Image
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: [BUG] Messed up Projection-Matrices

Post by hybrid »

Just google for dx projection matrices and find the Irrlicht values there. If you can solve the question of why there are two different versions, or if you do find reasons to change from one to the other, just tell us. Right now I only see that your equations give some values that you did not expect. That's pretty vague for asking to change one of the most fundamental parts of a render engine.
gerdb
Posts: 194
Joined: Wed Dec 02, 2009 8:21 pm
Location: Dresden, Germany

Re: [BUG] Messed up Projection-Matrices

Post by gerdb »

hi,

yesterday i did not look into irr-sourcecode, today i did and found that all created projection matrices loose information because of not stored matrix-cells

when i have 6 independant vars (Left, Right, Top, Bottom, Near, Far), but i only write to 4 matrix-cells in each buildProjectionMatrix[...] then i loose information.

so i cant reconstruct all 6 values, despite my equations.

But I dont know why that is not visible in console-output (i guess for symmetrical its zero )

the other thing was D3D to OGL, if irr creates D3D matrices i read that i need to Scale and Translate the matrix before trying to extract the values, i dont do this right now
but ill look into that when i have time

My creation fun

Code: Select all

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;
}
Irrlicht OrthoLH Pls look at my comments Information-Loss

Code: Select all

    // Builds a left-handed orthogonal projection matrix.
    template <class T>
    inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoLH(
            f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
    {
        _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
        _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
        _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
        M[0] = (T)(2/widthOfViewVolume);
        M[1] = 0;
        M[2] = 0;
        M[3] = 0;
 
        M[4] = 0;
        M[5] = (T)(2/heightOfViewVolume);
        M[6] = 0;
        M[7] = 0;
 
        M[8] = 0;
        M[9] = 0;
        M[10] = (T)(1/(zFar-zNear)); // i have -2 as factor
        M[11] = 0;
 
        M[12] = 0; // Information loss
        M[13] = 0; // Information loss
        M[14] = (T)(zNear/(zNear-zFar));
        M[15] = 1;
 
#if defined ( USE_MATRIX_TEST )
        definitelyIdentityMatrix=false;
#endif
        return *this;
    }
Irrlicht PerspectiveLH Pls look at my comments Information-Loss

Code: Select all

    // Builds a left-handed perspective projection matrix.
    template <class T>
    inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveLH(
            f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
    {
        _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
        _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
        _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
        M[0] = (T)(2*zNear/widthOfViewVolume);
        M[1] = 0;
        M[2] = 0;
        M[3] = 0;
 
        M[4] = 0;
        M[5] = (T)(2*zNear/heightOfViewVolume);
        M[6] = 0;
        M[7] = 0;
 
        M[8] = 0; // Information loss
        M[9] = 0; // Information loss
        M[10] = (T)(zFar/(zFar-zNear));
        M[11] = 1;
 
        M[12] = 0;
        M[13] = 0;
        M[14] = (T)(zNear*zFar/(zNear-zFar));
        M[15] = 0;
#if defined ( USE_MATRIX_TEST )
        definitelyIdentityMatrix=false;
#endif
        return *this;
    }


I dont know exactly if M[0], M[1], M[2], M[3] is the first column of the matrices, but i thought of it this way when commenting ( Column wise-saving?)

thx
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: [BUG] Messed up Projection-Matrices

Post by CuteAlien »

Sorry, but I have a little trouble right now understanding what it is exactly you are trying to tell.

Why is there an information loss? I mean your function makes sense probably, but it seems the existing functions just do what their interface says they will do (not using 6 parameters but the 4 they say they use). So what you want to have is a new function which doesn't just create symmetrical projections? Or is there a bug in the existing functions where you comment that information loss happens?

NOTE: Btw. I agree that a non-symmetrical projection might be fun sometimes (although the only use I can think of for that right now is creating a "drunken" effect).
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
gerdb
Posts: 194
Joined: Wed Dec 02, 2009 8:21 pm
Location: Dresden, Germany

Re: [BUG] Messed up Projection-Matrices

Post by gerdb »

hi,

maybe youre right if the missing cells are always zero its no error by irrlicht, but im really missing the glFrustum equivalent.

When i use GL and irrlicht produces D3D Matrices, then where is the transform from D3D to OGL in COpenGLDriver.cpp, i cant find it. Pls tell me, then i would add this to my fun
and maybe then the results are better.

i found setBasicRender2dStates the things for ortho, but i dont find them for 3d

Code: Select all

 
            core::matrix4 m(core::matrix4::EM4CONST_NOTHING);
            m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-(s32)(renderTargetSize.Height)), -1.0f, 1.0f);
            m.setTranslation(core::vector3df(-1,1,0));
Or is there a bug in the existing functions where you comment that information loss happens?
After much looking i guess that what irr does is correct (i found your dx projection google hint and it seems right), but not that what i need.

EDIT: in setBasic3drenderstates if found this at the beginning

Code: Select all

        glMatrixMode(GL_PROJECTION);
        glLoadMatrixf(Matrices[ETS_PROJECTION].pointer());
why dont i get it, isnt this still a D3D matrix?

thx

EDIT: why i need it
I know there probably isn't much use for a perspective camera with an asymmetric frustum (a camera frustum where the near and far clipping planes are not centered on the Z axis) in most games, but we have found that Unity (sry for that :-) ) is great for authoring immersive simulation environments and in these environments, one often needs to create asymmetric camera frustums (frusta?) to render large, near-field view projection screens from the "sweet spot" view of audience members so that the scene they are viewing does not look distorted. This usually requires an asymmetric camera frustum.
i found this on the web too, and it tells exactly what im trying to do in a nicer way i could express.
gerdb
Posts: 194
Joined: Wed Dec 02, 2009 8:21 pm
Location: Dresden, Germany

Re: [BUG] Messed up Projection-Matrices

Post by gerdb »

hi,

i got a strange result when using buildProjectionMatrixPerspectiveLH/RH with OpenGL Driver

Code: Select all

    ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(0);
    if (camera)
    {
        camera->setPosition( vector3df(0,30,-40) );
        camera->setTarget( vector3df(0,5,0));
        core::matrix4 m = core::IdentityMatrix;
        m.buildProjectionMatrixPerspectiveLH( (f32)driver->getScreenSize().Width, (f32)driver->getScreenSize().Height, 1, 1000);
        camera->setProjectionMatrix(m, false);
    }
the projection is distorted and i dont know why, my D3D function creates exactly the same matrix, but is distorted too.

with HelloWorld Example there is nothing to see.

Hope its not me,

thx

Code: Select all

/** Example 001 HelloWorld
 
This Tutorial shows how to set up the IDE for using the Irrlicht Engine and how
to write a simple HelloWorld program with it. The program will show how to use
the basics of the VideoDriver, the GUIEnvironment, and the SceneManager.
Microsoft Visual Studio is used as an IDE, but you will also be able to
understand everything if you are using a different one or even another
operating system than windows.
 
You have to include the header file <irrlicht.h> in order to use the engine. The
header file can be found in the Irrlicht Engine SDK directory \c include. To let
the compiler find this header file, the directory where it is located has to be
specified. This is different for every IDE and compiler you use. Let's explain
shortly how to do this in Microsoft Visual Studio:
 
- If you use Version 6.0, select the Menu Extras -> Options.
  Select the directories tab, and select the 'Include' Item in the combo box.
  Add the \c include directory of the irrlicht engine folder to the list of
  directories. Now the compiler will find the Irrlicht.h header file. We also
  need the irrlicht.lib to be found, so stay in that dialog, select 'Libraries'
  in the combo box and add the \c lib/VisualStudio directory.
  \image html "vc6optionsdir.jpg"
  \image latex "vc6optionsdir.jpg"
  \image html "vc6include.jpg"
  \image latex "vc6include.jpg"
 
- If your IDE is Visual Studio .NET, select Tools -> Options.
  Select the projects entry and then select VC++ directories. Select 'show
  directories for include files' in the combo box, and add the \c include
  directory of the irrlicht engine folder to the list of directories. Now the
  compiler will find the Irrlicht.h header file. We also need the irrlicht.lib
  to be found, so stay in that dialog, select 'show directories for Library
  files' and add the \c lib/VisualStudio directory.
  \image html "vcnetinclude.jpg"
  \image latex "vcnetinclude.jpg"
 
That's it. With your IDE set up like this, you will now be able to develop
applications with the Irrlicht Engine.
 
Lets start!
 
After we have set up the IDE, the compiler will know where to find the Irrlicht
Engine header files so we can include it now in our code.
*/
#include <irrlicht.h>
 
/*
In the Irrlicht Engine, everything can be found in the namespace 'irr'. So if
you want to use a class of the engine, you have to write irr:: before the name
of the class. For example to use the IrrlichtDevice write: irr::IrrlichtDevice.
To get rid of the irr:: in front of the name of every class, we tell the
compiler that we use that namespace from now on, and we will not have to write
irr:: anymore.
*/
using namespace irr;
 
/*
There are 5 sub namespaces in the Irrlicht Engine. Take a look at them, you can
read a detailed description of them in the documentation by clicking on the top
menu item 'Namespace List' or by using this link:
http://irrlicht.sourceforge.net/docu/namespaces.html
Like the irr namespace, we do not want these 5 sub namespaces now, to keep this
example simple. Hence, we tell the compiler again that we do not want always to
write their names.
*/
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
 
/*
To be able to use the Irrlicht.DLL file, we need to link with the Irrlicht.lib.
We could set this option in the project settings, but to make it easy, we use a
pragma comment lib for VisualStudio. On Windows platforms, we have to get rid
of the console window, which pops up when starting a program with main(). This
is done by the second pragma. We could also use the WinMain method, though
losing platform independence then.
*/
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
 
 
/*
This is the main method. We can now use main() on every platform.
*/
int main()
{
    /*
    The most important function of the engine is the createDevice()
    function. The IrrlichtDevice is created by it, which is the root
    object for doing anything with the engine. createDevice() has 7
    parameters:
 
    - deviceType: Type of the device. This can currently be the Null-device,
       one of the two software renderers, D3D8, D3D9, or OpenGL. In this
       example we use EDT_SOFTWARE, but to try out, you might want to
       change it to EDT_BURNINGSVIDEO, EDT_NULL, EDT_DIRECT3D8,
       EDT_DIRECT3D9, or EDT_OPENGL.
 
    - windowSize: Size of the Window or screen in FullScreenMode to be
       created. In this example we use 640x480.
 
    - bits: Amount of color bits per pixel. This should be 16 or 32. The
       parameter is often ignored when running in windowed mode.
 
    - fullscreen: Specifies if we want the device to run in fullscreen mode
       or not.
 
    - stencilbuffer: Specifies if we want to use the stencil buffer (for
       drawing shadows).
 
    - vsync: Specifies if we want to have vsync enabled, this is only useful
       in fullscreen mode.
 
    - eventReceiver: An object to receive events. We do not want to use this
       parameter here, and set it to 0.
 
    Always check the return value to cope with unsupported drivers,
    dimensions, etc.
    */
    IrrlichtDevice *device =
        createDevice( video::EDT_SOFTWARE, dimension2d<u32>(640, 480), 16,
            false, false, false, 0);
 
    if (!device)
        return 1;
 
    /*
    Set the caption of the window to some nice text. Note that there is an
    'L' in front of the string. The Irrlicht Engine uses wide character
    strings when displaying text.
    */
    device->setWindowCaption(L"Hello World! - Irrlicht Engine Demo");
 
    /*
    Get a pointer to the VideoDriver, the SceneManager and the graphical
    user interface environment, so that we do not always have to write
    device->getVideoDriver(), device->getSceneManager(), or
    device->getGUIEnvironment().
    */
    IVideoDriver* driver = device->getVideoDriver();
    ISceneManager* smgr = device->getSceneManager();
    IGUIEnvironment* guienv = device->getGUIEnvironment();
 
    /*
    We add a hello world label to the window, using the GUI environment.
    The text is placed at the position (10,10) as top left corner and
    (260,22) as lower right corner.
    */
    guienv->addStaticText(L"Hello World! This is the Irrlicht Software renderer!",
        rect<s32>(10,10,260,22), true);
 
    /*
    To show something interesting, we load a Quake 2 model and display it.
    We only have to get the Mesh from the Scene Manager with getMesh() and add
    a SceneNode to display the mesh with addAnimatedMeshSceneNode(). We
    check the return value of getMesh() to become aware of loading problems
    and other errors.
 
    Instead of writing the filename sydney.md2, it would also be possible
    to load a Maya object file (.obj), a complete Quake3 map (.bsp) or any
    other supported file format. By the way, that cool Quake 2 model
    called sydney was modelled by Brian Collins.
    */
    IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
    if (!mesh)
    {
        device->drop();
        return 1;
    }
    IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
 
    /*
    To let the mesh look a little bit nicer, we change its material. We
    disable lighting because we do not have a dynamic light in here, and
    the mesh would be totally black otherwise. Then we set the frame loop,
    such that the predefined STAND animation is used. And last, we apply a
    texture to the mesh. Without it the mesh would be drawn using only a
    color.
    */
    if (node)
    {
        node->setMaterialFlag(EMF_LIGHTING, false);
        node->setMD2Animation(scene::EMAT_STAND);
        node->setMaterialTexture( 0, driver->getTexture("../../media/sydney.bmp") );
    }
 
    /*
    To look at the mesh, we place a camera into 3d space at the position
    (0, 30, -40). The camera looks from there to (0,5,0), which is
    approximately the place where our md2 model is.
    */
    ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(0);
    if (camera)
    {
        camera->setPosition( vector3df(0,30,-40) );
        camera->setTarget( vector3df(0,5,0));
        core::matrix4 m = core::IdentityMatrix;
        m.buildProjectionMatrixPerspectiveLH( (f32)driver->getScreenSize().Width, (f32)driver->getScreenSize().Height, 1, 1000);
        camera->setProjectionMatrix(m, false);
    }
 
    /*
    Ok, now we have set up the scene, lets draw everything: We run the
    device in a while() loop, until the device does not want to run any
    more. This would be when the user closes the window or presses ALT+F4
    (or whatever keycode closes a window).
    */
    while(device->run())
    {
        /*
        Anything can be drawn between a beginScene() and an endScene()
        call. The beginScene() call clears the screen with a color and
        the depth buffer, if desired. Then we let the Scene Manager and
        the GUI Environment draw their content. With the endScene()
        call everything is presented on the screen.
        */
        driver->beginScene(true, true, SColor(255,100,101,140));
 
        smgr->drawAll();
        guienv->drawAll();
 
        driver->endScene();
    }
 
    /*
    After we are done with the render loop, we have to delete the Irrlicht
    Device created before with createDevice(). In the Irrlicht Engine, you
    have to delete all objects you created with a method or function which
    starts with 'create'. The object is simply deleted by calling ->drop().
    See the documentation at irr::IReferenceCounted::drop() for more
    information.
    */
    device->drop();
 
    return 0;
}
 
/*
That's it. Compile and run.
**/
 
distorted using buildProjectionMatrixPerspectiveLH
Image

how it should be using buildProjectionMatrixPerspectiveFovLH
Image

there was some progress switching zNear with zFar -> so zNear = 1000, zFar = 1, but was not usable either
gerdb
Posts: 194
Joined: Wed Dec 02, 2009 8:21 pm
Location: Dresden, Germany

Re: [BUG] Messed up Projection-Matrices

Post by gerdb »

i got it,

width and height are for the Near plane so best is a Aspect Ratio as width and 1 as height for a near value == 1 ( when width > height )

Code: Select all

projMat.buildProjectionMatrixPerspectiveLH( 
                 (f32)driver->getScreenSize().Width / (f32)driver->getScreenSize().Height,
       1.f,
       1.f, 10000.f );
 
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: [BUG] Messed up Projection-Matrices

Post by hybrid »

You shouldn't take the OpenGL/D3D thing too seriously, or maybe just different. D3D uses left-handed systems, while OpenGL uses right-handed. That is - by default. You can use any system with any coords system. So we use left-handed for both. You don't need to change a thing for OpenGL, you shouldn't just use pure OpenGL methods which would expect right-handed coords and rely on this. That's why there is no problem currently with Irrlicht system setup. If you need different things, we may add different (and separate) methods. But it would need some very good justifications.
gerdb
Posts: 194
Joined: Wed Dec 02, 2009 8:21 pm
Location: Dresden, Germany

Re: [no bug] Messed up Projection-Matrices

Post by gerdb »

hi thx for your help, i now got it to work, since i rely on the D3D matrices.

I guess we can move this thread somewhere else.

Here is my next problem and id like to ask for your advices:

i got a function that renders a scene to a large image. but each tile-rendering leads to different result, due to OnAnimate( differentTime ),

can i disable these animations before i render more than one time or freeze the scene in one state until im done rendering?

thx
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: [unconfirmed] Messed up Projection-Matrices

Post by hendu »

Yes, you can stop the timer.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: [unconfirmed] Messed up Projection-Matrices

Post by hybrid »

the timer also only ticks if you call run or tick. Otherwise the time should be always the same.
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Re: [unconfirmed] Messed up Projection-Matrices

Post by Mel »

It is a bit hard to set properly the projection matrices for each graphics API, while DirectX uses left handed matrices, OpenGL uses right handed ones, nothing to worry, because it is more or less easy to transform from one to another, but there is also another issue with the projection matrices, they convert from non normalized to normalized space, and in Direct X the normalized space goes from (-1,-1,0) to (1,1,1), while in OpenGL it goes from (-1,-1,-1) to (1,1,1) and in GL the zDepth is inverse (1 is closer than 0 to the screen), while in Direct X it goes as expected, being 0 the closest distance and 1 the farthest value.

Irrlicht, by default, uses left-handed, DX compatible matrices, and thus, any projection matrix should conform to the DirectX properties for a projection matrix, they should convert the world space geometry to the range from (-1,-1,0) to (1,1,1) and shouldn't invert the Z values.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
Fury.
Posts: 25
Joined: Mon Dec 20, 2010 2:03 pm

Re: [unconfirmed] Messed up Projection-Matrices

Post by Fury. »

just take some code from Ogre matrices and most stuff will be repaired.
Post Reply