[SOLVED] Change shader color parameter on keypress?

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
pandoragami
Posts: 226
Joined: Wed Jan 26, 2011 5:37 pm
Contact:

[SOLVED] Change shader color parameter on keypress?

Post by pandoragami »

I hacked the 10th tutorial on shaders by moving part of the code into a function call

Code: Select all

 
void shader_init( float a, float r, float g, float b)
{
    if (gpu)
    {
        mc = new MyShaderCallBack();
        mc->init_color(a,r,g,b);
 
        // create the shaders depending on if the user wanted high level
        // or low level shaders:
 
        if (UseHighLevelShaders)
        {
            // create material from high level shaders (hlsl or glsl)
 
            newMaterialType1 = gpu->addHighLevelShaderMaterialFromFiles(
                vsFileName, "vertexMain", video::EVST_VS_1_1,
                psFileName, "pixelMain", video::EPST_PS_1_1,
                mc, video::EMT_SOLID);
 
            newMaterialType2 = gpu->addHighLevelShaderMaterialFromFiles(
                vsFileName, "vertexMain", video::EVST_VS_1_1,
                psFileName, "pixelMain", video::EPST_PS_1_1,
                mc, video::EMT_TRANSPARENT_ADD_COLOR);
        }
        else
        {
            // create material from low level shaders (asm or arb_asm)
 
            newMaterialType1 = gpu->addShaderMaterialFromFiles(vsFileName,
                psFileName, mc, video::EMT_SOLID);
 
            newMaterialType2 = gpu->addShaderMaterialFromFiles(vsFileName,
                psFileName, mc, video::EMT_TRANSPARENT_ADD_COLOR);
        }
 
        mc->drop();
    }
}
and I changed the MyShaderCallBack with a method for changing the color on a key press in the game loop.

Code: Select all

if(receiver.IsKeyDown(irr::KEY_KEY_B))      
            shader_init(0.0f,255.0f,0.0f,255.0f);   
But unfortunately this is not the right way about this. Is there a more specific method for changing the shader color (and other parameters as well)? I looked at the documentation
http://irrlicht.sourceforge.net/docu/cl ... _back.html

But only 2 methods exist in irr::video::IShaderConstantSetCallBack and neither of which allow changing the shader during runtime.

Here's the complete code,

Code: Select all

 
#include <irrlicht.h>
using namespace irr;
 
bool UseHighLevelShaders = false;
IrrlichtDevice* device = 0;
 
class MyShaderCallBack : public video::IShaderConstantSetCallBack
{
public:
 
    video::SColorf col;
 
    void init_color(int a, int r, int g, int b)
    {
        col.set(a,r,g,b);
    }
 
    virtual void OnSetConstants(video::IMaterialRendererServices* services,
            s32 userData)
    {
        video::IVideoDriver* driver = services->getVideoDriver();
 
        // set inverted world matrix
        // if we are using highlevel shaders (the user can select this when
        // starting the program), we must set the constants by name.
 
        core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD);
        invWorld.makeInverse();
 
        if (UseHighLevelShaders)
            services->setVertexShaderConstant("mInvWorld", invWorld.pointer(), 16);
        else
            services->setVertexShaderConstant(invWorld.pointer(), 0, 4);
 
        // set clip matrix
 
        core::matrix4 worldViewProj;
        worldViewProj = driver->getTransform(video::ETS_PROJECTION);
        worldViewProj *= driver->getTransform(video::ETS_VIEW);
        worldViewProj *= driver->getTransform(video::ETS_WORLD);
 
        if (UseHighLevelShaders)
            services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
        else
            services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4);
 
        // set camera position
 
        core::vector3df pos = device->getSceneManager()->
            getActiveCamera()->getAbsolutePosition();
 
        if (UseHighLevelShaders)
            services->setVertexShaderConstant("mLightPos", reinterpret_cast<f32*>(&pos), 3);
        else
            services->setVertexShaderConstant(reinterpret_cast<f32*>(&pos), 8, 1);
 
        if (UseHighLevelShaders)
            services->setVertexShaderConstant("mLightColor",
                    reinterpret_cast<f32*>(&col), 4);
        else
            services->setVertexShaderConstant(reinterpret_cast<f32*>(&col), 9, 1);
 
        // set transposed world matrix
 
        core::matrix4 world = driver->getTransform(video::ETS_WORLD);
        world = world.getTransposed();
 
        if (UseHighLevelShaders)
            services->setVertexShaderConstant("mTransWorld", world.pointer(), 16);
        else
            services->setVertexShaderConstant(world.pointer(), 10, 4);
    }
};
 
class MyEventReceiver : public IEventReceiver
{
public:
    // This is the one method that we have to implement
    virtual bool OnEvent(const SEvent& event)
    {
        // Remember whether each key is down or up
        if (event.EventType == irr::EET_KEY_INPUT_EVENT)
            KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
 
        return false;
    }
 
    // This is used to check whether a key is being held down
    virtual bool IsKeyDown(EKEY_CODE keyCode) const
    {
        return KeyIsDown[keyCode];
    }
 
    MyEventReceiver()
    {
        for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
            KeyIsDown[i] = false;
    }
 
private:
    // We use this array to store the current state of each key
    bool KeyIsDown[KEY_KEY_CODES_COUNT];
};
 
MyEventReceiver receiver;
MyShaderCallBack* mc;
video::IGPUProgrammingServices* gpu;
s32 newMaterialType1 = 0;
s32 newMaterialType2 = 0;
io::path vsFileName; // filename for the vertex shader
io::path psFileName; // filename for the pixel shader
void shader_init( float a, float r, float g, float b);
 
int main()
{
    UseHighLevelShaders = true;
 
    device = createDevice( video::EDT_OPENGL, core::dimension2d<u32>(640, 480), 16, false, false, false, &receiver);
 
    if (device == 0)
        return 1;
 
    video::IVideoDriver* driver = device->getVideoDriver();
    scene::ISceneManager* smgr = device->getSceneManager();
 
    if (UseHighLevelShaders)
    {
        psFileName = "opengl.frag";
        vsFileName = "opengl.vert";
    }
    else
    {
        psFileName = "opengl.psh";
        vsFileName = "opengl.vsh";
    }
 
    if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
        !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1))
    {
        device->getLogger()->log("WARNING: Pixel shaders disabled "\
            "because of missing driver/hardware support.");
        psFileName = "";
    }
 
    if (!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
        !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1))
    {
        device->getLogger()->log("WARNING: Vertex shaders disabled "\
            "because of missing driver/hardware support.");
        vsFileName = "";
    }
 
    gpu = driver->getGPUProgrammingServices();
    shader_init(0.0f,0.0f,0.0f,255.0f);
 
    scene::ICameraSceneNode* cam = smgr->addCameraSceneNodeFPS( 0, 50.0f, 0.01f, -1, 0, 0, false, 0.0f, false, true);
    cam->setPosition(core::vector3df( -100,50,100));
    cam->setTarget(core::vector3df( 0, 0, 0));
 
    device->getCursorControl()->setVisible(false);
 
    scene::ISceneNode* node = smgr->addCubeSceneNode(50);
    node->setPosition(core::vector3df(0,0,0));
    node->setMaterialTexture(0, driver->getTexture("wall.bmp"));
    node->setMaterialFlag(video::EMF_LIGHTING, false);
    node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType1);
 
    int lastFPS = -1;
 
    while(device->run())
    {
        driver->beginScene(true, true, video::SColor(255,0,0,0));
        smgr->drawAll();
        driver->endScene();
        int fps = driver->getFPS();
 
        if (lastFPS != fps)
        {
            core::stringw str = L"[";
            str += " FPS:  ";
            str += fps;
            str += "]";
 
            device->setWindowCaption(str.c_str());
            lastFPS = fps;
        }
 
        if(receiver.IsKeyDown(irr::KEY_KEY_B))      
            shader_init(0.0f,255.0f,0.0f,255.0f);       
 
        device->sleep(50);
    }
 
    device->drop();
 
    return 0;
}
void shader_init( float a, float r, float g, float b)
{
    if (gpu)
    {
        mc = new MyShaderCallBack();
        mc->init_color(a,r,g,b);
 
        // create the shaders depending on if the user wanted high level
        // or low level shaders:
 
        if (UseHighLevelShaders)
        {
            // create material from high level shaders (hlsl or glsl)
 
            newMaterialType1 = gpu->addHighLevelShaderMaterialFromFiles(
                vsFileName, "vertexMain", video::EVST_VS_1_1,
                psFileName, "pixelMain", video::EPST_PS_1_1,
                mc, video::EMT_SOLID);
 
            newMaterialType2 = gpu->addHighLevelShaderMaterialFromFiles(
                vsFileName, "vertexMain", video::EVST_VS_1_1,
                psFileName, "pixelMain", video::EPST_PS_1_1,
                mc, video::EMT_TRANSPARENT_ADD_COLOR);
        }
        else
        {
            // create material from low level shaders (asm or arb_asm)
 
            newMaterialType1 = gpu->addShaderMaterialFromFiles(vsFileName,
                psFileName, mc, video::EMT_SOLID);
 
            newMaterialType2 = gpu->addShaderMaterialFromFiles(vsFileName,
                psFileName, mc, video::EMT_TRANSPARENT_ADD_COLOR);
        }
 
        mc->drop();
    }
}
 
Last edited by pandoragami on Sat Mar 14, 2015 6:09 pm, edited 1 time in total.
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Change shader color parameter on keypress?

Post by mongoose7 »

You created two new material types but you haven't added them to the materials in use for your models.

Code: Select all

node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType1);
is called only once.
pandoragami
Posts: 226
Joined: Wed Jan 26, 2011 5:37 pm
Contact:

Re: Change shader color parameter on keypress?

Post by pandoragami »

mongoose7 wrote:You created two new material types but you haven't added them to the materials in use for your models.

Code: Select all

node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType1);
is called only once.

Thanks it works now, here's the corrected code, pressing B changes the color of the cube to teal. By the way is there any simpler method for doing this, without having to call
the shader_init( float a, float r, float g, float b) just to change the color. I also wondered if I should worry about memory leaks, you don't think there are any right? If not this is fine.

Code: Select all

 
#include <irrlicht.h>
 
 
using namespace irr;
 
bool UseHighLevelShaders = false;
IrrlichtDevice* device = 0;
 
class MyShaderCallBack : public video::IShaderConstantSetCallBack
{
public:
 
    video::SColorf col;
 
    void init_color(int a, int r, int g, int b)
    {
        col.set(a,r,g,b);
    }
 
    virtual void OnSetConstants(video::IMaterialRendererServices* services,
            s32 userData)
    {
        video::IVideoDriver* driver = services->getVideoDriver();
 
        // set inverted world matrix
        // if we are using highlevel shaders (the user can select this when
        // starting the program), we must set the constants by name.
 
        core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD);
        invWorld.makeInverse();
 
        if (UseHighLevelShaders)
            services->setVertexShaderConstant("mInvWorld", invWorld.pointer(), 16);
        else
            services->setVertexShaderConstant(invWorld.pointer(), 0, 4);
 
        // set clip matrix
 
        core::matrix4 worldViewProj;
        worldViewProj = driver->getTransform(video::ETS_PROJECTION);
        worldViewProj *= driver->getTransform(video::ETS_VIEW);
        worldViewProj *= driver->getTransform(video::ETS_WORLD);
 
        if (UseHighLevelShaders)
            services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
        else
            services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4);
 
        // set camera position
 
        core::vector3df pos = device->getSceneManager()->
            getActiveCamera()->getAbsolutePosition();
 
        if (UseHighLevelShaders)
            services->setVertexShaderConstant("mLightPos", reinterpret_cast<f32*>(&pos), 3);
        else
            services->setVertexShaderConstant(reinterpret_cast<f32*>(&pos), 8, 1);
 
        if (UseHighLevelShaders)
            services->setVertexShaderConstant("mLightColor",
                    reinterpret_cast<f32*>(&col), 4);
        else
            services->setVertexShaderConstant(reinterpret_cast<f32*>(&col), 9, 1);
 
        // set transposed world matrix
 
        core::matrix4 world = driver->getTransform(video::ETS_WORLD);
        world = world.getTransposed();
 
        if (UseHighLevelShaders)
            services->setVertexShaderConstant("mTransWorld", world.pointer(), 16);
        else
            services->setVertexShaderConstant(world.pointer(), 10, 4);
    }
};
 
class MyEventReceiver : public IEventReceiver
{
public:
    // This is the one method that we have to implement
    virtual bool OnEvent(const SEvent& event)
    {
        // Remember whether each key is down or up
        if (event.EventType == irr::EET_KEY_INPUT_EVENT)
            KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
 
        return false;
    }
 
    // This is used to check whether a key is being held down
    virtual bool IsKeyDown(EKEY_CODE keyCode) const
    {
        return KeyIsDown[keyCode];
    }
 
    MyEventReceiver()
    {
        for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
            KeyIsDown[i] = false;
    }
 
private:
    // We use this array to store the current state of each key
    bool KeyIsDown[KEY_KEY_CODES_COUNT];
};
 
MyEventReceiver receiver;
MyShaderCallBack* mc;
video::IGPUProgrammingServices* gpu;
s32 newMaterialType1 = 0;
io::path vsFileName; // filename for the vertex shader
io::path psFileName; // filename for the pixel shader
void shader_init( float a, float r, float g, float b);
 
int main()
{
    UseHighLevelShaders = true;
 
    device = createDevice( video::EDT_OPENGL, core::dimension2d<u32>(640, 480), 16, false, false, false, &receiver);
 
    if (device == 0)
        return 1;
 
    video::IVideoDriver* driver = device->getVideoDriver();
    scene::ISceneManager* smgr = device->getSceneManager();
 
    if (UseHighLevelShaders)
    {
        psFileName = "opengl.frag";
        vsFileName = "opengl.vert";
    }
    else
    {
        psFileName = "opengl.psh";
        vsFileName = "opengl.vsh";
    }
 
    if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
        !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1))
    {
        device->getLogger()->log("WARNING: Pixel shaders disabled "\
            "because of missing driver/hardware support.");
        psFileName = "";
    }
 
    if (!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
        !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1))
    {
        device->getLogger()->log("WARNING: Vertex shaders disabled "\
            "because of missing driver/hardware support.");
        vsFileName = "";
    }
 
    gpu = driver->getGPUProgrammingServices();
    shader_init(0.0f,0.0f,0.0f,255.0f);
 
    scene::ICameraSceneNode* cam = smgr->addCameraSceneNodeFPS( 0, 50.0f, 0.01f, -1, 0, 0, false, 0.0f, false, true);
    cam->setPosition(core::vector3df( -100,50,100));
    cam->setTarget(core::vector3df( 0, 0, 0));
 
    device->getCursorControl()->setVisible(false);
 
    scene::ISceneNode* node = smgr->addCubeSceneNode(50);
    node->setPosition(core::vector3df(0,0,0));
    node->setMaterialTexture(0, driver->getTexture("wall.bmp"));
    node->setMaterialFlag(video::EMF_LIGHTING, false);
    node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType1);
 
    int lastFPS = -1;
 
    while(device->run())
    {
        driver->beginScene(true, true, video::SColor(255,0,0,0));
        smgr->drawAll();
        driver->endScene();
        int fps = driver->getFPS();
 
        if (lastFPS != fps)
        {
            core::stringw str = L"[";
            str += " FPS:  ";
            str += fps;
            str += "]";
 
            device->setWindowCaption(str.c_str());
            lastFPS = fps;
        }
 
        if(receiver.IsKeyDown(irr::KEY_KEY_B))
        {
            shader_init(0.0f,255.0f,0.0f,255.0f);
            node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType1);
        }
 
        device->sleep(50);
    }
 
    device->drop();
 
    return 0;
}
void shader_init( float a, float r, float g, float b)
{
    if (gpu)
    {
        mc = new MyShaderCallBack();
        mc->init_color(a,r,g,b);
 
        // create the shaders depending on if the user wanted high level
        // or low level shaders:
 
        if (UseHighLevelShaders)
        {
            // create material from high level shaders (hlsl or glsl)
 
            newMaterialType1 = gpu->addHighLevelShaderMaterialFromFiles(
                vsFileName, "vertexMain", video::EVST_VS_1_1,
                psFileName, "pixelMain", video::EPST_PS_1_1,
                mc, video::EMT_SOLID);
        }
        else
        {
            // create material from low level shaders (asm or arb_asm)
 
            newMaterialType1 = gpu->addShaderMaterialFromFiles(vsFileName,
                psFileName, mc, video::EMT_SOLID);
        }
 
        mc->drop();
    }
}
 
 
 
 
 
 
 
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Change shader color parameter on keypress?

Post by hendu »

Yes, there's a much lighter way. Instead of keeping a reference to the material type, keep a reference to the callback class instance, and simply call its init_color when the color needs changing.
pandoragami
Posts: 226
Joined: Wed Jan 26, 2011 5:37 pm
Contact:

Re: Change shader color parameter on keypress?

Post by pandoragami »

hendu wrote:Yes, there's a much lighter way. Instead of keeping a reference to the material type, keep a reference to the callback class instance, and simply call its init_color when the color needs changing.
I made mc global and put mc->drop(); just before the device->drop();

thanks for the all the help!
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

Re: [SOLVED] Change shader color parameter on keypress?

Post by thanhle »

Hi Mate,
This works fine on static mesh.

Have you find a work around to apply this on animated mesh?

From what I think, before using shader, for animated mesh we create a texture with the color on the fly, and blend it with existing texture.
Do we using the same method for shader?
Any tip to do that using Shader method to change animated mesh color?

Thanks
thanh
pandoragami
Posts: 226
Joined: Wed Jan 26, 2011 5:37 pm
Contact:

Re: [SOLVED] Change shader color parameter on keypress?

Post by pandoragami »

thanhle wrote:Hi Mate,
This works fine on static mesh.

Have you find a work around to apply this on animated mesh?

From what I think, before using shader, for animated mesh we create a texture with the color on the fly, and blend it with existing texture.
Do we using the same method for shader?
Any tip to do that using Shader method to change animated mesh color?

Thanks
thanh
I've only tried this on a custom mesh besides that nothing else (except for the examples I already posted with the scenenodecube), best of luck to you!
Post Reply