Proper instancing support

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Proper instancing support

Post by hendu »

http://sourceforge.net/p/irrlicht/patches/268/

Image

Finally, proper instancing support, none of the slower and/or VRAM-wasting hacks. ;)

The test scene had 1000 cubes. With the default mode, it used 100% of one core, and produced 140 fps. Using the new instancing, it used < 4% of one core, while outputting 360 fps.

Here's the test app:

Code: Select all

 
#include <irrlicht.h>
 
#define USE_INSTANCED 1
 
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
 
static const char vtex[] =
    "#extension GL_ARB_draw_instanced: enable\n"
    "uniform sampler2D tex;"
    "uniform mat4 viewp;"
    "attribute vec4 color;"
    "attribute mat4 model;"
 
    "void main() {"
#if USE_INSTANCED
        "gl_Position = viewp * model * gl_Vertex;"
        "gl_FrontColor = color;"
#else
        "gl_Position = ftransform();"
        "gl_FrontColor = vec4(gl_MultiTexCoord0.xy, vec2(1.0));"
#endif
    "}";
 
static const char ftex[] =
    "void main() {"
        "gl_FragColor = vec4(gl_Color);"
    "}";
 
class scb_t: public IShaderConstantSetCallBack {
public:
    virtual void OnSetConstants(IMaterialRendererServices* srv, s32) {
        IVideoDriver* drv = srv->getVideoDriver();
 
        matrix4 viewp = drv->getTransform(ETS_PROJECTION);
        viewp *= drv->getTransform(ETS_VIEW);
 
        srv->setVertexShaderConstant("viewp", viewp.pointer(), 16);
    }
} scb;
 
int main() {
 
    IrrlichtDevice *dev = createDevice(EDT_OPENGL);
    if (!dev) return 1;
 
    IVideoDriver *drv = dev->getVideoDriver();
    ISceneManager* smgr = dev->getSceneManager();
 
    IMesh *m = smgr->getGeometryCreator()->createCubeMesh(vector3df(1));
    ICameraSceneNode *cam = smgr->addCameraSceneNodeFPS(0, 100, 0.03);
    cam->setPosition(vector3df(0, 30, 0));
    cam->setTarget(vector3df(0));
 
    int shader = drv->getGPUProgrammingServices()->addHighLevelShaderMaterial(
                vtex, ftex, &scb);
    if (shader < 0) return 1;
 
    SMaterial &cubemat = m->getMeshBuffer(0)->getMaterial();
    cubemat.Lighting = false;
    cubemat.MaterialType = (E_MATERIAL_TYPE) shader;
 
    u32 i;
 
#if !USE_INSTANCED
    for (i = 0; i < 1000; i++) {
        smgr->addMeshSceneNode(m, 0, -1,
            (vector3df(i / 100, (i / 10) % 10, i % 10) * 2) - 10);
    }
#else
    IInstancedMeshSceneNode *n = smgr->addInstancedMeshSceneNode(m);
 
    for (i = 0; i < 1000; i++) {
        n->addInstance((vector3df(i / 100, (i / 10) % 10, i % 10) * 2) - 10);
        n->setInstanceColor(i, SColor(255, i/4, 0, 0));
    }
#endif
 
    int oldfps = 0;
    while (dev->run()) {
        drv->beginScene();
        smgr->drawAll();
        drv->endScene();
 
        int fps = drv->getFPS();
        if (fps != oldfps) {
            wchar_t tmp[80];
            swprintf(tmp, 80, L"fps %u, %u tris. Mode: %s", fps,
                drv->getPrimitiveCountDrawn(),
                USE_INSTANCED ? "instanced" : "normal");
 
            dev->setWindowCaption(tmp);
            oldfps = fps;
        }
    }
 
    dev->drop();
 
    return 0;
}
 
As you can see, you can toggle the mode with the top define, and the changes to use instancing are quite small. I quite like the API I came up with for IInstancedMeshSceneNode, it lets you control each instance individually, and defers changes until necessary.

Please take a look at the user-facing API, and post any feedback:

Code: Select all

 
// Copyright (C) 2013 Lauri Kasanen
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
 
#ifndef __I_INSTANCED_MESH_SCENE_NODE_H_INCLUDED__
#define __I_INSTANCED_MESH_SCENE_NODE_H_INCLUDED__
 
#include "IMeshSceneNode.h"
 
namespace irr
{
namespace scene
{
    //! Scene node to render many instances of a static mesh.
    /** This scene node allows you to use geometry instancing on
        supported hardware (dx9 cards and up). This means you can
        render a crowd/forest/etc with just one draw call.
 
        You will need to write a shader to use this node, instancing
        is not supported using the fixed pipeline.
 
        You may use the colors to send any custom per-instance data.
        */
    class IInstancedMeshSceneNode : public IMeshSceneNode
    {
    public:
 
        //! Constructor
        IInstancedMeshSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
            IMesh *mesh = NULL, u32 initialInstances = 0,
            const core::vector3df& position = core::vector3df(0,0,0),
            const core::vector3df& rotation = core::vector3df(0,0,0),
            const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f))
            : IMeshSceneNode(parent, mgr, id, position, rotation, scale) {}
 
        //! Destructor
        virtual ~IInstancedMeshSceneNode() {}
 
        //! Add a new instance.
        virtual void addInstance(
            const core::vector3df& position = core::vector3df(0,0,0),
            const core::vector3df& rotation = core::vector3df(0,0,0),
            const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f),
            const video::SColor& color = video::SColor(255, 255, 255, 255)) = 0;
 
        //! Get the number of instances
        virtual u32 getInstanceCount() const = 0;
 
        //! Sets the position of this instance.
        /** \param num: Number of the instance to edit.
            \param pos: New position, relative to this scene node. */
        virtual void setInstancePosition(u32 num, const core::vector3df& pos) = 0;
 
        //! Sets the rotation of this instance.
        /** \param num: Number of the instance to edit.
            \param rot: New rotation, relative to this scene node. */
        virtual void setInstanceRotation(u32 num, const core::vector3df& rot) = 0;
 
        //! Sets the scale of this instance.
        /** \param num: Number of the instance to edit.
            \param scale: New scale, relative to this scene node. */
        virtual void setInstanceScale(u32 num, const core::vector3df& scale) = 0;
 
        //! Sets the color of this instance.
        /** \param num: Number of the instance to edit.
            \param col: New color. */
        virtual void setInstanceColor(u32 num, const video::SColor& col) = 0;
 
        //! Set the names of the vertex attributes
        /** By default, the color is bound to "color", and the model/world
            matrix of each instance is bound to "model". */
        virtual void setAttributeNames(const char *color, const char *model) = 0;
    };
 
} // end namespace scene
} // end namespace irr
 
#endif
 
You can easily control each instance separately from this interface.

The custom vertex attribute code (the last patch of the branch, "Custom VA - a bit hacky") is the only part that is not ready to be applied, as some better way for that should be found. But it works as is, so you can check out the branch if you want to test this feature.

The attrib code doesn't apply straight to trunk, and the GL extension wrappers also need manual applying. The user-facing API and the added count in draw calls should apply cleanly.
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Proper instancing support

Post by hendu »

This app looks better from the dark side :P

Image
Granyte
Posts: 850
Joined: Tue Jan 25, 2011 11:07 pm
Contact:

Re: Proper instancing support

Post by Granyte »

There was already a patch for instancing how ever I haven't really read the OGL part so maybe your is better on that.

But is yours limited to OGL? as I wrote DX support for the other patch
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Proper instancing support

Post by hendu »

There was already a patch for instancing how ever I haven't really read the OGL part so maybe your is better on that.
The ones I saw were "fake", they replicated meshes in VRAM - they were worse than the proper technique in both memory and speed. Could you link the one you mean?

Yes, this patch only carries OpenGL support.

Line counts seem to divide up nicely:
Image
Granyte
Posts: 850
Joined: Tue Jan 25, 2011 11:07 pm
Contact:

Re: Proper instancing support

Post by Granyte »

http://irrlicht.sourceforge.net/forum/v ... 0&start=30

this is the one I mean it work for both ogl and DX it use true hardware instancing for openGL and DX as far as I know and I only implemented mesh batching in the demo for comparison

the upload is to page 3

but anyway I saw that you use custom vertex attribute is this how you transmit the per instance data?
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Proper instancing support

Post by hendu »

I forgot about that, it seems I even reviewed it back then, 8 months ago ;)

This is a bit cleaner, and comes with an integrated SceneNode.
but anyway I saw that you use custom vertex attribute is this how you transmit the per instance data?
Yes. Sending matrices over uniforms is far too limited, they are not meant for that. With the proper technique it's one draw call, and uniform space is not wasted; with the 62 limit, you have N/62 drawcalls, and not a lot of space for your own uniforms.
Granyte
Posts: 850
Joined: Tue Jan 25, 2011 11:07 pm
Contact:

Re: Proper instancing support

Post by Granyte »

I guess I should update the DX version to your method as it's the better one and anyway the hack I used to get the uniform pass-through working in DX is UGLY but i'm a bit to lazy to do it since the FVF will come out with 2.0 forcing a complete rewrite of it.
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Proper instancing support

Post by hendu »

To be honest, it may be 2016 before we see 2.0, based on casual observation of the release speed...


Re FVF, this is kind of tangential to it. FVF is about formatting the vertex stream, while instanced arrays cannot be in the same buffer as the vertex data.

The only part of FVF that would be re-used is the data type wrapper - E_SOMETHING_FLOAT to GL_FLOAT. Of course the render function may need adjustments if the GL driver changes, but those should be minor.
Granyte
Posts: 850
Joined: Tue Jan 25, 2011 11:07 pm
Contact:

Re: Proper instancing support

Post by Granyte »

ya but in DX I would have to re write partially the FVF to make this hack work and even worst not using the FVF would prevent the user from sending custom data to it's shader per instance
RdR
Competition winner
Posts: 273
Joined: Tue Mar 29, 2011 2:58 pm
Contact:

Re: Proper instancing support

Post by RdR »

Is there a link for the complete patch?
And is this patch for trunk or FVF branch?
Would be nice to see it for FVF branch imho :D
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Proper instancing support

Post by hendu »

There is no "complete patch" as in a single huge blob. It's broken out on purpose, for easier reviewing.
If someone dropped a 1.1k line patch on me, I'd pretty much laugh them out the room ;)

It's for trunk. (well originally for my 1.7 branch)
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Proper instancing support

Post by hendu »

I checked the FVF branch. This does not conflict, it's as I thought earlier, only the type enum would be used.
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Proper instancing support

Post by hendu »

Now using the type enum from the FVF branch. Nadro, separating it similarly in the FVF branch would help there too, as it would remove that one big case-block from the drawVertexPrimitiveList function.
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Re: Proper instancing support

Post by Nadro »

When we'll finish tasks related to mobile platforms, I'll switch again to shader-pipeline branch, where this stuff (or similar) should be available. Instancing is really important feature, but it will be not available before v2.0. Anyway stable v2.0 should be available in first half of 2014, so in trunk those features will be available in 2013.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Proper instancing support

Post by hendu »

Instancing does not depend on FVF, so from my POV it could go to 1.9 just fine. Are the plans for 1.9 already made, or?
Post Reply