History: Heat Shimmer Manager
Source of version: 5 (current)
Copy to clipboard
{img src="img/wiki_up/Heat_sprite.png" align="right"}
Created for the purpose to easily create multiple heat shimmers either via ((-scene|scene)) loader or manually, and manage the shader in general.
{maketoc}
!!Usage
Include ''HeatShimmerManager.h'' in your project, make sure the needed scripts are in place, create your manager object, and after the scene is loaded, call its ''initialize(bool)'' function.
If you use a scene loader, name your scene nodes where you want the heat shimmer effect to begin with "HeatSystem_". Same goes with bones on skeletal entities. If you use either, it would be best to call ''initialize(true)'', as that goes through and looks for those named elements.
HeatShimmerManager relies heavily on the systems being a certain name, and being a certain amount of systems. As such, there is not yet a remove function, however in case of changing scenes, the manager has a ''reset()'' function that will clear the ((-SceneManager)) of the particle system and the HeatShimmerManager of how many particle systems there are.
For manual adding of systems, there are add functions.
!!Code
!!!HeatShimmerManager
{CODE(wrap="1", colors="c++")} /*
-----------------------------------------------------------------------------
Filename: HeatShimmerManager.h
-----------------------------------------------------------------------------
This is the source file to create and manage multiple instances of the heat
shimmer particle shader.
Uses OGRE
(Object-oriented Graphics Rendering Engine)
Copyright (c) 2000-2009 The OGRE Team
For the latest info, see http://www.ogre3d.org/
While OGRE is under the LGPL, this file is in the public domain, and may be
used for whatever you like.
If your -SceneManager or loader can have user data attached to nodes,
you can modify the addHeat and setHeatParticle functions to load user data
to modify the particle system. I did not do this because from what I can tell,
there are different user data systems that store it differently.
By Shadowking97 @ Ogre 3d forums
-----------------------------------------------------------------------------
*/
#ifndef __HeatShimmerManager_H__
#define __HeatShimmerManager_H__
#include "Ogre.h"
#include "OgreStringConverter.h"
#include "OgreException.h"
using namespace Ogre;
//Renderable Listener combined with RenderTargetListener to black out non-heat related
//renderables
class HeatRenderableListener: public RenderTargetListener, RenderQueue::RenderableListener
{
private:
SceneManager* mSceneMgr;
Camera* cam;
//Number of heat particle emmiters.
int numParticles;
RenderQueue* queue;
public:
HeatRenderableListener(SceneManager* scene, Camera* c, int p): cam(c)
{
numParticles = p;
mSceneMgr = scene;
queue = mSceneMgr->getRenderQueue();
}
void preRenderTargetUpdate(const RenderTargetEvent& evt)
{
// Todo: Set non-heat related soft particles to black while keeping alpha
//set heat particle camera to the same loc/rot of the default camera
mSceneMgr->getCamera("HeatCam")->setPosition(cam->getPosition());
mSceneMgr->getCamera("HeatCam")->setOrientation(cam->getOrientation());
//Set heat particles visible and set renderablelistener
for(int i = 0;i<numParticles;i++)
mSceneMgr->getParticleSystem("HeatParticleSystem_"+StringConverter::toString(i))->setVisible(true);
queue->setRenderableListener(this);
}
void postRenderTargetUpdate(const RenderTargetEvent& evt)
{
// Reset the heat particles and RenderableListener
for(int i = 0;i<numParticles;i++)
mSceneMgr->getParticleSystem("HeatParticleSystem_"+StringConverter::toString(i))->setVisible(false);
queue->setRenderableListener(0);
}
bool renderableQueued(Renderable* rend, uint8 groupID,
ushort priority, Technique** ppTech, RenderQueue* pQueue)
{
//If renderable's technique isn't the Technique from Particle/Heat,
//Renderable is not a heat particle so set the technique to Darkness
Technique* tech = *ppTech;
if(tech->getParent()->getName()!="Particle/Heat")
{
MaterialPtr mat = MaterialManager::getSingleton().getByName("Heat/Darkness");
tech = mat->getTechnique(0);
*ppTech = tech;
}
return true;
}
};
//Main manager for heat particles.
class HeatShimmerManager
{
private:
//Main render camera
Camera* mCamera;
//Camera created for heat rendering
Camera* mHeatCam;
SceneManager* mSceneMgr;
RenderTexture* heatRender;
RenderWindow* mWindow;
//Number of particle systems
int particleCount;
public:
HeatShimmerManager(Camera* MainCam, SceneManager* MainScene, RenderWindow* win): mCamera(MainCam), mSceneMgr(MainScene), mWindow(win)
{
particleCount=0;
}
/* HeatShimmerManager::Initialize(bool)
Used to initialize Heat Shimmer Manager.
Sets up the heat camera, viewport, render texture
Adds Renderable/RenderTarget Lisstener to the texture
Adds Heat Compositor
Call this function after the scene has been set up inbetween the compositors
you want the heat wave to go.
@setUpParticles
If true, calls functions to search for nodes and bones
named for particle system attachment.
*/
void initialize(bool setUpParticles)
{
mHeatCam = mSceneMgr->createCamera("HeatCam");
mHeatCam->setNearClipDistance(mCamera->getNearClipDistance());
mHeatCam->setFarClipDistance(mCamera->getFarClipDistance());
mHeatCam->setAspectRatio(mCamera->getAspectRatio());
mHeatCam->setFOVy (mCamera->getFOVy());
mHeatCam->setOrientation(mCamera->getOrientation());
mHeatCam->setPosition(mCamera->getPosition());
TexturePtr heatTex = TextureManager::getSingleton().createManual("heat",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, mWindow->getWidth()/2,
mWindow->getHeight()/2, 0, PF_R8G8B8, TU_RENDERTARGET);
heatRender = heatTex->getBuffer()->getRenderTarget();
heatRender->addViewport(mHeatCam);
heatRender->getViewport(0)->setClearEveryFrame(true);
heatRender->getViewport(0)->setBackgroundColour(ColourValue::Black);
heatRender->getViewport(0)->setOverlaysEnabled(false);
heatRender->setAutoUpdated(true);
if(setUpParticles)
{
setHeatParticles(mSceneMgr->getRootSceneNode());
setBonedHeatParticles();
}
HeatRenderableListener * heatListener = new HeatRenderableListener(mSceneMgr,mCamera,particleCount);
heatRender->addListener(heatListener);
CompositorManager::getSingleton().addCompositor(mCamera->getViewport(), "heat_waves");
CompositorManager::getSingleton().setCompositorEnabled(mCamera->getViewport(),"heat_waves",true);
}
/* HeatShimmerManager::reset()
Clears the Heat Shimmer and -Scene Managers of all particle systems.
*/
void reset()
{
for(int i = 0; i<particleCount;i++)
{
mSceneMgr->destroyParticleSystem("HeatParticleSystem_"+StringConverter::toString(i));
}
particleCount=0;
}
//Manual heat particle creation on SceneNode
void addHeat(SceneNode* n)
{
ParticleSystem* heat_Particles = mSceneMgr->createParticleSystem("HeatParticleSystem_"+StringConverter::toString(particleCount), "Render/Heat");
particleCount++;
n->attachObject(heat_Particles);
heat_Particles->setVisible(false);
}
//Manual heat particle creation on SceneNode
void addHeat(String sceneNodeName)
{
ParticleSystem* heat_Particles = mSceneMgr->createParticleSystem("HeatParticleSystem_"+StringConverter::toString(particleCount), "Render/Heat");
particleCount++;
mSceneMgr->getSceneNode(sceneNodeName)->attachObject(heat_Particles);
heat_Particles->setVisible(false);
}
//Manual heat particle creation on Entity bone
void addHeatToBone(Bone* b, Entity* e)
{
ParticleSystem* heat_Particles = mSceneMgr->createParticleSystem("HeatParticleSystem_"+StringConverter::toString(particleCount), "Render/Heat");
particleCount++;
e->attachObjectToBone(b->getName(),heat_Particles);
heat_Particles->setVisible(false);
}
//Manual heat particle creation on Entity bone
void addHeatToBone(String boneName, Entity* e)
{
ParticleSystem* heat_Particles = mSceneMgr->createParticleSystem("HeatParticleSystem_"+StringConverter::toString(particleCount), "Render/Heat");
particleCount++;
e->attachObjectToBone(boneName,heat_Particles);
heat_Particles->setVisible(false);
}
protected:
/*
setHeatParticles(SceneNode*)
Goes through the scene recursivly via root scene node
attaching ParticleSystems for heat to the apropriate
nodes.
*/
void setHeatParticles(SceneNode* node)
{
if(node->getName().find("HeatSystem_")!=-1)
{
ParticleSystem* heat_Particles = mSceneMgr->createParticleSystem("HeatParticleSystem_"+StringConverter::toString(particleCount), "Render/Heat");
particleCount++;
node->attachObject(heat_Particles);
heat_Particles->setVisible(false);
}
Node::ChildNodeIterator iterator = node->getChildIterator();
while(iterator.hasMoreElements())
{
SceneNode* n = dynamic_cast<SceneNode*>(iterator.getNext());
if(n)
setHeatParticles(n);
}
}
/*
setBonedHeatParticles()
Goes through Entities in a scene and attaches heat particles
to the appropriate bones.
*/
void setBonedHeatParticles()
{
SceneManager::MovableObjectIterator iterator = mSceneMgr->getMovableObjectIterator("Entity");
while(iterator.hasMoreElements())
{
Entity* e = static_cast<Entity*>(iterator.getNext());
if(e->hasSkeleton()&&e->isInScene())
{
SkeletonInstance* s = e->getSkeleton();
Skeleton::BoneIterator bones = s->getBoneIterator();
while(bones.hasMoreElements())
{
Bone* bone = static_cast<Bone*>(bones.getNext());
if(bone->getName().find("HeatSystem_")!=-1)
{
ParticleSystem* heat_Particles = mSceneMgr->createParticleSystem("HeatParticleSystem_"+StringConverter::toString(particleCount), "Render/Heat");
particleCount++;
e->attachObjectToBone(bone->getName(),heat_Particles);
heat_Particles->setVisible(false);
}
}
}
}
}
};
#endif
{CODE}
!!!Particles
{CODE(wrap="1", colors="c++")} particle_system Render/Heat
{
quota 1500
material Particle/Heat
particle_width 1
particle_height 1
cull_each true
renderer billboard
billboard_type point
emitter Box
{
angle 73.17
colour 1 1 1 1
colour_range_start 1 1 1 1
colour_range_end 1 1 1 1
direction 0 0 1
emission_rate 500
position 0 0 0
velocity 8
velocity_min 8
velocity_max 8
time_to_live 1.5
time_to_live_min 1.5
time_to_live_max 1.5
duration 0
duration_min 0
duration_max 0
repeat_delay 0
repeat_delay_min 0
repeat_delay_max 0
width 10
height 10
depth 10
}
affector LinearForce
{
force_vector 0 9.8 0
force_application add
}
affector ColourFader
{
red -0.2967
green -0.2768
blue -0.7465
alpha 0
}
}
{CODE}
!!!Materials
{CODE(wrap="1", colors="c++")} material Particle/Heat
{
technique
{
pass
{
lighting off
depth_write off
scene_blend add
texture_unit
{
texture heat_sprite.png
}
}
}
}
material Heat/Darkness
{
technique
{
pass
{
lighting off
texture_unit
{
texture darkness.png
}
}
}
}
fragment_program Distortion/Heat_ps cg
{
source heat_Distortion.cg
entry_point main
profiles ps_2_0 arbfp1
default_params
{
param_named distortionScale float 2
}
}
material Ogre/Compositor/Heat_wave
{
technique
{
pass
{
depth_check off
vertex_program_ref Ogre/Compositor/StdQuad_Cg_vp
{
}
fragment_program_ref Distortion/Heat_ps
{
}
texture_unit Texture0
{
tex_coord_set 0
tex_address_mode clamp
filtering linear linear linear
}
texture_unit Texture1
{
texture heat
tex_coord_set 1
tex_address_mode clamp
filtering linear linear linear
}
}
}
}
{CODE}
!!!Compositor
{CODE(wrap="1", colors="c++")} compositor heat_waves
{
technique
{
texture main target_width target_height PF_R8G8B8
target main
{
input previous
}
target_output
{
input none
pass render_quad
{
material Ogre/Compositor/Heat_wave
input 0 main
}
}
}
}
{CODE}
!!!heat_Distortion.cg
{CODE(wrap="1", colors="c++")} sampler Texture0 : register(s0);
sampler Texture1 : register(s1);
float distortionScale;
float4 main(float2 texCoord : TEXCOORD0) : COLOR
{
float2 distort = tex2D(Texture1,texCoord).xy;
return tex2D(Texture0, texCoord - distortionScale*(distort/100*(texCoord-0.5)));
}
{CODE}
!!Images Used
{img src="img/wiki_up/Darkness.png" alt="darkness.png"}
{img src="img/wiki_up/Heat_sprite.png" alt="heat_sprite.png"}