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
Table of contents
Files
You will need to add these files to your resources:
glow.material
Copy to clipboard
// *** 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 } } } }
ps_glow.glsl
Copy to clipboard
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; }
vs_glow.glsl
Copy to clipboard
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); }
ps_glow.cg
Copy to clipboard
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; }
vs_glow.cg
Copy to clipboard
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); }
StencilOpQueueListener.h (add to your sources)
Copy to clipboard
#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
Usage
Set the RenderQueue Listener
Copy to clipboard
StencilOpQueueListener* stencilOpFrameListener; stencilOpFrameListener = new StencilOpQueueListener(); mSceneMgr->addRenderQueueListener(stencilOpFrameListener);
Set the entities that will glow
Copy to clipboard
// 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);
To disable, just remove the glow entity from the SceneNode:
Copy to clipboard
actualOutlineGlowNode->detachObject(actualOutlineGlowEntity); mSceneMgr->destroyEntity(actualOutlineGlowEntity);
Please note that this technique does not work well with stencil shadows
Written by sercero