[Solved] Need help with fire shader, animate with time?

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] Need help with fire shader, animate with time?

Post by pandoragami »

I recently discovered this thread

http://irrlicht.sourceforge.net/forum/v ... p?t=20976# called "3 rt and 1 fire shader(HLSL)"

and I decided to convert it to glsl and so far I think I've manually translated the shaders properly but for some reason the texture loads on the billboard and looks almost like it could run but the "time" component doesn't seem to work.

Basically the flame effect doesn't run and just stays at one state.

Here's the code
main.cpp

Code: Select all

 
#include <irrlicht.h>
#include <iostream>
 
using namespace irr;
 
IrrlichtDevice* device = 0;
bool UseHighLevelShaders = false;
bool UseCgShaders = false;
 
irr::scene::ILightSceneNode* light_node = NULL;
irr::scene::ISceneNode* node = NULL;
 
class MyShaderCallBack : public video::IShaderConstantSetCallBack
{
public:
 
    virtual void OnSetConstants(video::IMaterialRendererServices* services,
            s32 userData)
    {
        video::IVideoDriver* driver = services->getVideoDriver();
 
        core::matrix4 proj = driver->getTransform(video::ETS_PROJECTION);
        core::matrix4 view = driver->getTransform(video::ETS_VIEW);
        core::matrix4 world = driver->getTransform(video::ETS_WORLD);
 
        core::matrix4 worldViewProj;
        worldViewProj = driver->getTransform(video::ETS_PROJECTION);
        worldViewProj *= driver->getTransform(video::ETS_VIEW);
        worldViewProj *= driver->getTransform(video::ETS_WORLD);
 
        services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
 
        float time  = (float)device->getTimer()->getTime();
            services->setVertexShaderConstant("time", &time, 1);
 
        s32 TextureLayerID = 0;
        services->setPixelShaderConstant("fire_base", &TextureLayerID, 1);
 
        TextureLayerID = 1;
        services->setPixelShaderConstant("fire_distortion", &TextureLayerID, 1);
 
        TextureLayerID = 2;
        services->setPixelShaderConstant("fire_opacity", &TextureLayerID, 1);
    }
};
int main()
{
    video::E_DRIVER_TYPE driverType;
    UseHighLevelShaders = true;
    UseCgShaders =false;
 
    // create device
    device = createDevice(irr::video::EDT_OPENGL, core::dimension2d<u32>(640, 480));
 
    if (device == 0)
        return 1;
 
    video::IVideoDriver* driver = device->getVideoDriver();
    scene::ISceneManager* smgr = device->getSceneManager();
    gui::IGUIEnvironment* gui = device->getGUIEnvironment();
 
    if (UseCgShaders && !driver->queryFeature(video::EVDF_CG))
    {
        printf("Warning: No Cg support, disabling.\n");
        UseCgShaders=false;
    }
 
    io::path vsFileName;
    io::path psFileName;
 
    driverType = video::EDT_OPENGL;
    psFileName = "opengl.frag";
    vsFileName = "opengl.vert";
 
    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 = "";
    }
 
    video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();
    s32 newMaterialType1 = 0;
    s32 newMaterialType2 = 0;
 
    if (gpu)
    {
        MyShaderCallBack* mc = new MyShaderCallBack();
 
 
        if (UseHighLevelShaders)
        {
 
            const video::E_GPU_SHADING_LANGUAGE shadingLanguage =
                UseCgShaders ? video::EGSL_CG:video::EGSL_DEFAULT;
 
 
            newMaterialType1 = gpu->addHighLevelShaderMaterialFromFiles(
                vsFileName, "vertexMain", video::EVST_VS_1_1,
                psFileName, "pixelMain", video::EPST_PS_1_1,
                mc, video::EMT_SOLID, 0, shadingLanguage);
 
            newMaterialType2 = gpu->addHighLevelShaderMaterialFromFiles(
                vsFileName, "vertexMain", video::EVST_VS_1_1,
                psFileName, "pixelMain", video::EPST_PS_1_1,
                mc, video::EMT_TRANSPARENT_ADD_COLOR, 0 , shadingLanguage);
        }
        else
        {
 
            newMaterialType1 = gpu->addShaderMaterialFromFiles(vsFileName,
                psFileName, mc, video::EMT_SOLID);
 
            newMaterialType2 = gpu->addShaderMaterialFromFiles(vsFileName,
                psFileName, mc, video::EMT_TRANSPARENT_ADD_COLOR);
        }
 
        mc->drop();
    }
 
    node = smgr->addEmptySceneNode( 0,-1);
    node->setPosition( irr::core::vector3df( 0, 0, 0));
 
    light_node = smgr->addLightSceneNode(0, core::vector3df( 0, 0, 0),
        video::SColorf(1.0f, 0.6f, 0.7f, 1.0f), 50.0f);
 
    irr::video::SLight  & slight = light_node->getLightData();
    slight.Type = irr::video::ELT_DIRECTIONAL;
 
    slight.AmbientColor = irr::video::SColorf(1.0f,0.0f,0.0f,0.0f);
    slight.SpecularColor = irr::video::SColorf(1.0f,1.0f,1.0f,0.0f);
    slight.DiffuseColor = irr::video::SColorf(1.0f,1.0f,1.0f,0.0f);
 
    node->addChild( light_node);
 
    irr::scene::ISceneNodeAnimator* anim = 0;
 
    anim = smgr->createRotationAnimator ( irr::core::vector3df( 0.0f, 0.6f, 0.0f));
 
        node->addAnimator(anim);
        anim->drop();
 
    scene::ISceneNode* cubenode = smgr->addBillboardSceneNode(
      0, core::dimension2d<f32>(50.0f, 50.0f));
    cubenode->setMaterialTexture( 0, driver->getTexture("../../textures/b.png"));
    cubenode->setMaterialTexture( 1, driver->getTexture("../../textures/a.png"));
    cubenode->setMaterialTexture( 2, driver->getTexture("../../textures/flame.png"));
    cubenode->setMaterialFlag(video::EMF_LIGHTING, false);
    cubenode->setMaterialFlag(video::EMF_BLEND_OPERATION, true);
    cubenode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
    cubenode->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType2);
 
    scene::ICameraSceneNode* cam = smgr->addCameraSceneNode();
    cam->setPosition(core::vector3df(-45,45,-45));
    cam->setTarget(core::vector3df(0,0,0));
    device->getCursorControl()->setVisible( false);
 
    int lastFPS = -1;
 
    while(device->run())
        if (device->isWindowActive())
    {
        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"Irrlicht Engine - Vertex and pixel shader example [";
            str += driver->getName();
            str += "] FPS:";
            str += fps;
 
            device->setWindowCaption(str.c_str());
            lastFPS = fps;
        }
    }
 
    device->drop();
 
    return 0;
}
 
/*
Compile and run this, and I hope you have fun with your new little shader
writing tool :).
**/
 
 
opengl.frag

Code: Select all

 
uniform sampler2D fire_base;
uniform sampler2D fire_distortion;
uniform sampler2D fire_opacity;
 
varying vec2 TexCoord0;
varying vec2 TexCoord1;
varying vec2 TexCoord2;
varying vec2 TexCoord3;
 
vec4 bx2( vec4 x)
{
   return 2.0 * x - 1.0;
}
void main()
{   
   float distortion_amount0  = 0.092;
   float distortion_amount1  = 0.092;
   float distortion_amount2  = 0.092;
   
   vec4 height_attenuation = vec4(0.3, 0.39, 0.0, 1.0);
   
   vec4 noise0 = texture2D( fire_distortion, TexCoord1);
   vec4 noise1 = texture2D( fire_distortion, TexCoord2);
   vec4 noise2 = texture2D( fire_distortion, TexCoord3);    
   
   vec4 noiseSum = bx2( noise0) * distortion_amount0 + 
          bx2( noise1) * distortion_amount1 + bx2( noise2) * distortion_amount2;
   
   vec2 perturbedBaseCoords;
 
   perturbedBaseCoords.x = TexCoord0.x + noiseSum.x * (TexCoord0.y * 
         height_attenuation.x + height_attenuation.y);
        
   perturbedBaseCoords.y = TexCoord0.y + noiseSum.y * (TexCoord0.y * 
         height_attenuation.x + height_attenuation.y);
         
   vec4 base = texture2D( fire_base, perturbedBaseCoords);
   base *= 1.5f;
   vec4 opacity = texture2D( fire_opacity, perturbedBaseCoords);
   
   gl_FragColor = base*opacity;
}
 
 

opengl.vert

Code: Select all

 
varying vec2 TexCoord0;
varying vec2 TexCoord1;
varying vec2 TexCoord2;
varying vec2 TexCoord3;
uniform mat4 mWorldViewProj;
float time;
 
void main()
{
    gl_Position = mWorldViewProj * gl_Vertex;   
    gl_TexCoord[0] = gl_MultiTexCoord0; 
    
    vec4 layer_speed = vec4( 0.2, 0.52, 0.1, 1.0);
    
    TexCoord0 = gl_TexCoord[0].st;
    TexCoord0 += 0.2;       
    
    TexCoord1.x = gl_TexCoord[0].s;
    TexCoord1.y = gl_TexCoord[0].t + layer_speed.x * time/1000.0f;
    
    TexCoord2.x = gl_TexCoord[0].s;
    TexCoord2.y = gl_TexCoord[0].t + layer_speed.y * time/1000.0f;
    
    TexCoord3.x = gl_TexCoord[0].s;
    TexCoord3.y = gl_TexCoord[0].t + layer_speed.z * time/1000.0f;  
} 
 
 

The textures

a.png -> https://imgur.com/pMUHN0m
b.png -> https://imgur.com/dBd8Mat
flame.png -> https://imgur.com/BxEPHDc

All textures on one page.

https://imgur.com/a/T3q3N
Last edited by pandoragami on Wed Dec 20, 2017 3:14 am, edited 3 times in total.
devsh
Competition winner
Posts: 2057
Joined: Tue Dec 09, 2008 6:00 pm
Location: UK
Contact:

Re: Need help with fire shader, unable to animate with time?

Post by devsh »

you forgot to declare "time" as uniform (possibly a typo on your end).
pandoragami
Posts: 226
Joined: Wed Jan 26, 2011 5:37 pm
Contact:

Re: Need help with fire shader, unable to animate with time?

Post by pandoragami »

devsh wrote:you forgot to declare "time" as uniform (possibly a typo on your end).
OMG! I spent 2 to 3 hours now trying to solve this. This is hilarious, but hey, without your help I might have spent another day dealing with syntax. I do have one more question. Is there a way to shift the flame from the left a little to the center? If not I'll just try tweaking code and post the answer myself eventually.
pandoragami
Posts: 226
Joined: Wed Jan 26, 2011 5:37 pm
Contact:

Re: Need help with fire shader, unable to animate with time?

Post by pandoragami »

I made a small change in the fragment shader

Code: Select all

 
 
vec4 bx2( vec4 x)
{
   return 1.05 * x - 2.1;
}
 
 
and now it looks like the flame is centered, anyone have other ideas feel free to chime in.
devsh
Competition winner
Posts: 2057
Joined: Tue Dec 09, 2008 6:00 pm
Location: UK
Contact:

Re: [Solved] Need help with fire shader, animate with time?

Post by devsh »

That's why I changed the shader API in my engine, because currently you have no way of knowing if the set operation has succeeded.
(I spit out all active uniforms in a PostLink callback and it kinda your responsibility to map uniform locations to names via hashmap or more efficient means)
Post Reply