History: Stencil Glow
Source of version: 3 (current)
Copy to clipboard
This page explains how to add a glowing outline to your entities.
The code comes from the following forum post: https://forums.ogre3d.org/viewtopic.php?f=11&t=27477
!!Example
{img fileId="2309" thumb="box"}
{maketoc}
!!Files
You will need to add these files to your resources:
!!!glow.material
{CODE(wrap="1", colors="c++")}
// *** GLSL ***
vertex_program glow_vs_glsl glsl
{
source vs_glow.glsl
}
fragment_program glow_ps_glsl glsl
{
source ps_glow.glsl
}
material glow
{
technique
{
pass
{
scene_blend alpha_blend
depth_check on
lighting off
fragment_program_ref glow_ps_glsl
{
param_named_auto time time_0_x 100
param_named alpha_value float 0.4
}
vertex_program_ref glow_vs_glsl
{
param_named size_value float 1.1
param_named_auto time time_0_x 100
}
}
}
}
material alpha_glow
{
technique
{
pass
{
scene_blend alpha_blend
depth_check on
lighting off
fragment_program_ref glow_ps_glsl
{
param_named_auto time time_0_x 100
param_named alpha_value float 0.0
}
vertex_program_ref glow_vs_glsl
{
param_named size_value float 1.1
param_named_auto time time_0_x 100
}
}
pass
{
scene_blend alpha_blend
depth_check on
lighting off
fragment_program_ref glow_ps_glsl
{
param_named_auto time time_0_x 100
param_named alpha_value float 0.0
}
}
}
}
material no_depth_check_glow
{
technique
{
pass
{
scene_blend alpha_blend
depth_check off
lighting off
fragment_program_ref glow_ps_glsl
{
param_named_auto time time_0_x 100
param_named alpha_value float 0.4
}
vertex_program_ref glow_vs_glsl
{
param_named size_value float 1.1
param_named_auto time time_0_x 100
}
}
}
}
// *** CG ***
vertex_program glow_vs_cg cg
{
source vs_glow.cg
entry_point main
profiles vs_1_1 arbvp1
}
fragment_program glow_ps_cg cg
{
source ps_glow.cg
entry_point main
profiles ps_2_0 arbfp1
}
material cg/glow
{
technique
{
pass
{
scene_blend alpha_blend
depth_check on
lighting off
vertex_program_ref glow_vs_cg
{
param_named_auto worldViewProjMatrix worldviewproj_matrix
param_named size_value float 1.1
param_named_auto time time_0_x 100
}
fragment_program_ref glow_ps_cg
{
param_named alpha_value float 0.4
param_named_auto time time_0_x 100
}
}
}
}
material cg/alpha_glow
{
technique
{
pass
{
scene_blend alpha_blend
depth_check on
lighting off
fragment_program_ref glow_ps_cg
{
param_named_auto time time_0_x 100
param_named alpha_value float 0.0
}
vertex_program_ref glow_vs_cg
{
param_named_auto worldViewProjMatrix worldviewproj_matrix
param_named size_value float 1.1
param_named_auto time time_0_x 100
}
}
pass
{
scene_blend alpha_blend
depth_check on
lighting off
fragment_program_ref glow_ps_cg
{
param_named_auto time time_0_x 100
param_named alpha_value float 0.0
}
}
}
}
material cg/no_depth_check_glow
{
technique
{
pass
{
scene_blend alpha_blend
depth_check off
lighting off
fragment_program_ref glow_ps_cg
{
param_named_auto time time_0_x 100
param_named alpha_value float 0.4
}
}
pass
{
scene_blend alpha_blend
depth_check off
lighting off
fragment_program_ref glow_ps_cg
{
param_named_auto time time_0_x 100
param_named alpha_value float 0.4
}
vertex_program_ref glow_vs_cg
{
param_named_auto worldViewProjMatrix worldviewproj_matrix
param_named size_value float 1.1
param_named_auto time time_0_x 100
}
}
}
}
{CODE}
!!!ps_glow.glsl
{CODE(wrap="1", colors="c++")}
uniform float alpha_value;
uniform float time;
void main(void)
{
vec4 color;
color.x = 1.0;
color.y = 1.0;
color.z = 0.0;
color.w = alpha_value * ((sin(time * 5.0) + 1.0) / 2.0 );
gl_FragColor = color;
}
{CODE}
!!!vs_glow.glsl
{CODE(wrap="1", colors="c++")}
uniform float size_value;
uniform float time;
void main(void)
{
vec3 Pos = gl_Vertex.xyz + ( (size_value * (1.0 + (sin(time * 5.0) + 1.0) / 15.0 ) * normal );
gl_Position = gl_ModelViewProjectionMatrix * vec4(Pos, 1.0);
}
{CODE}
!!!ps_glow.cg
{CODE(wrap="1", colors="c++")}
float4 main( uniform float alpha_value,
uniform float time) : COLOR
{
float4 color;
color.x = 1.0;
color.y = 1.0;
color.z = 0.0;
color.w = alpha_value * ((sin(time * 5.0) / 3.14 + 1.0) / 2.0 );
return color;
}
{CODE}
!!!vs_glow.cg
{CODE(wrap="1", colors="c++")}
void main( float4 position : POSITION,
float3 normal : NORMAL,
float2 uv : TEXCOORD0,
out float4 oPosition : POSITION,
out float2 oUv : TEXCOORD0,
out float4 colour : COLOR,
uniform float4x4 worldViewProjMatrix,
uniform float size_value,
uniform float time)
{
float4 mypos = position;
mypos.xyz += size_value * (1.0 + (sin(time * 5.0) + 1.0) / 5.0 ) * normal;
oPosition = mul(worldViewProjMatrix, mypos);
}
{CODE}
!!!StencilOpQueueListener.h (add to your sources)
{CODE(wrap="1", colors="c++")}
#ifndef GLOW_H
#define GLOW_H
#include <OgreRoot.h>
#include <OgreRenderSystem.h>
#include <OgreRenderQueueListener.h>
// render queues
#define RENDER_QUEUE_OUTLINE_GLOW_OBJECTS Ogre::RenderQueueGroupID::RENDER_QUEUE_MAIN + 1
#define RENDER_QUEUE_OUTLINE_GLOW_GLOWS Ogre::RenderQueueGroupID::RENDER_QUEUE_MAIN + 2
#define RENDER_QUEUE_FULL_GLOW_ALPHA_GLOW Ogre::RenderQueueGroupID::RENDER_QUEUE_MAIN + 3
#define RENDER_QUEUE_FULL_GLOW_GLOW Ogre::RenderQueueGroupID::RENDER_QUEUE_MAIN + 4
#define LAST_STENCIL_OP_RENDER_QUEUE RENDER_QUEUE_FULL_GLOW_GLOW
// stencil values
#define STENCIL_VALUE_FOR_OUTLINE_GLOW 1
#define STENCIL_VALUE_FOR_FULL_GLOW 2
#define STENCIL_FULL_MASK 0xFFFFFFFF
// a Render queue listener to change the stencil mode
class StencilOpQueueListener : public Ogre::RenderQueueListener
{
public:
virtual void renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& skipThisInvocation)
{
if (queueGroupId == RENDER_QUEUE_OUTLINE_GLOW_OBJECTS) // outline glow object
{
Ogre::RenderSystem * rendersys = Ogre::Root::getSingleton().getRenderSystem();
// PORTABILIDAD: OGRE 1.11 se agrego el parametro: STENCIL_FULL_MASK
// https://www.ogre3d.org/docs/api/1.8/class_ogre_1_1_render_system.html
// https://ogrecave.github.io/ogre/api/1.11/class_ogre_1_1_render_system.html
rendersys->clearFrameBuffer(Ogre::FBT_STENCIL);
rendersys->setStencilCheckEnabled(true);
rendersys->setStencilBufferParams(Ogre::CompareFunction::CMPF_ALWAYS_PASS,
STENCIL_VALUE_FOR_OUTLINE_GLOW, STENCIL_FULL_MASK, STENCIL_FULL_MASK,
Ogre::StencilOperation::SOP_KEEP,Ogre::StencilOperation::SOP_KEEP,Ogre::StencilOperation::SOP_REPLACE, false);
}
if (queueGroupId == RENDER_QUEUE_OUTLINE_GLOW_GLOWS) // outline glow
{
Ogre::RenderSystem * rendersys = Ogre::Root::getSingleton().getRenderSystem();
rendersys->setStencilCheckEnabled(true);
rendersys->setStencilBufferParams(Ogre::CompareFunction::CMPF_NOT_EQUAL,
STENCIL_VALUE_FOR_OUTLINE_GLOW, STENCIL_FULL_MASK, STENCIL_FULL_MASK,
Ogre::StencilOperation::SOP_KEEP,Ogre::StencilOperation::SOP_KEEP,Ogre::StencilOperation::SOP_REPLACE,false);
}
if (queueGroupId == RENDER_QUEUE_FULL_GLOW_ALPHA_GLOW) // full glow - alpha glow
{
Ogre::RenderSystem * rendersys = Ogre::Root::getSingleton().getRenderSystem();
rendersys->setStencilCheckEnabled(true);
rendersys->setStencilBufferParams(Ogre::CompareFunction::CMPF_ALWAYS_PASS,
STENCIL_VALUE_FOR_FULL_GLOW,STENCIL_FULL_MASK, STENCIL_FULL_MASK,
Ogre::StencilOperation::SOP_KEEP,Ogre::StencilOperation::SOP_KEEP,Ogre::StencilOperation::SOP_REPLACE,false);
}
if (queueGroupId == RENDER_QUEUE_FULL_GLOW_GLOW) // full glow - glow
{
Ogre::RenderSystem * rendersys = Ogre::Root::getSingleton().getRenderSystem();
rendersys->setStencilCheckEnabled(true);
rendersys->setStencilBufferParams(Ogre::CompareFunction::CMPF_EQUAL,
STENCIL_VALUE_FOR_FULL_GLOW,STENCIL_FULL_MASK, STENCIL_FULL_MASK,
Ogre::StencilOperation::SOP_KEEP,Ogre::StencilOperation::SOP_KEEP,Ogre::StencilOperation::SOP_ZERO,false);
}
}
virtual void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation)
{
if ( queueGroupId == LAST_STENCIL_OP_RENDER_QUEUE )
{
Ogre::RenderSystem * rendersys = Ogre::Root::getSingleton().getRenderSystem();
rendersys->setStencilCheckEnabled(false);
rendersys->setStencilBufferParams();
}
}
};
#endif // GLOW_H
{CODE}
!!Usage
Set the RenderQueue Listener
{CODE(wrap="1", colors="c++")}
StencilOpQueueListener* stencilOpFrameListener;
stencilOpFrameListener = new StencilOpQueueListener();
mSceneMgr->addRenderQueueListener(stencilOpFrameListener);
{CODE}
Set the entities that will glow
{CODE(wrap="1", colors="c++")}
// outline glow entity
Ogre::Entity *outlineGlowEntity = mSceneMgr->createEntity("outlineGlow", "ogrehead.mesh");
outlineGlowEntity->setRenderQueueGroup(RENDER_QUEUE_OUTLINE_GLOW_OBJECTS);
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(outlineGlowEntity);
// outline glow entity actual glow
Ogre::Entity* actualOutlineGlowEntity = outlineGlowEntity->clone(outlineGlowEntity->getName() + "_glow");
actualOutlineGlowEntity->setRenderQueueGroup(RENDER_QUEUE_OUTLINE_GLOW_GLOWS);
actualOutlineGlowEntity->setMaterialName("cg/glow");
if(outlineGlowEntity->hasSkeleton()) // To make the glow animate with it's parent
actualOutlineGlowEntity->shareSkeletonInstanceWith(outlineGlowEntity);
Ogre::SceneNode* actualOutlineGlowNode = outlineGlowEntity->getParentSceneNode()->createChildSceneNode("outlineGlowNode");
actualOutlineGlowNode->attachObject(actualOutlineGlowEntity);
// normal entity
Ogre::Entity *normalOgreEntity = mSceneMgr->createEntity("normalOgreEntity", "ogrehead.mesh");
Ogre::SceneNode* normalOgreNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
normalOgreNode->attachObject(normalOgreEntity);
normalOgreNode->setPosition(80, 0, 0);
// full glow entity
Ogre::Entity *fullGlowEntity = mSceneMgr->createEntity("fullGlowEntity", "ogrehead.mesh");
Ogre::SceneNode* fullGlowNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
fullGlowNode->attachObject(fullGlowEntity);
fullGlowNode->setPosition(-80, 0, 0);
// full glow alpha glow
Ogre::Entity* alphaFullGlowEntity = fullGlowEntity->clone(fullGlowEntity->getName() + "_alphaGlow");
alphaFullGlowEntity->setRenderQueueGroup(RENDER_QUEUE_FULL_GLOW_ALPHA_GLOW);
alphaFullGlowEntity->setMaterialName("cg/alpha_glow");
if(fullGlowEntity->hasSkeleton()) // To make the glow animate with it's parent
alphaFullGlowEntity->shareSkeletonInstanceWith(fullGlowEntity);
Ogre::SceneNode* alphaFullGlowNode = fullGlowEntity->getParentSceneNode()->createChildSceneNode("fullGlowAlphaNode");
alphaFullGlowNode->attachObject(alphaFullGlowEntity);
// full glow alpha glow
Ogre::Entity* glowFullGlowEntity = fullGlowEntity->clone(fullGlowEntity->getName() + "_glow");
glowFullGlowEntity->setRenderQueueGroup(RENDER_QUEUE_FULL_GLOW_GLOW);
glowFullGlowEntity->setMaterialName("cg/no_depth_check_glow");
if(fullGlowEntity->hasSkeleton()) // To make the glow animate with it's parent
glowFullGlowEntity->shareSkeletonInstanceWith(fullGlowEntity);
Ogre::SceneNode* glowFullGlowNode = fullGlowEntity->getParentSceneNode()->createChildSceneNode("fullGlowGlowNode");
glowFullGlowNode->attachObject(glowFullGlowEntity);
{CODE}
To disable, just remove the glow entity from the SceneNode:
{CODE(wrap="1", colors="c++")}
actualOutlineGlowNode->detachObject(actualOutlineGlowEntity);
mSceneMgr->destroyEntity(actualOutlineGlowEntity);
{CODE}
Please note that this technique does not work well with stencil shadows
---
Written by ((User:sercero|sercero))