Skip to main content
GlowBalloon CG Shader        

So one day I was looking for shaders to use in my game involving cells when I came across this shader. Unfortunately it was a CGFX shader and ogre does not support .cgfx shaders. So I had to convert it to .cg.

It's not really that hard, actually, and this is coming from someone with next to zero shader knowledge. Just keep the manual pages close to hand :P

Capture93.PNG

The original shader. Note that I've removed the "#ifndef" stuff since it doesn't apply and everything between <angled brackets> because those are just stuff from the WYSIWYG editor (since it came with FX Composer).
I suggest you remove these too since they help clean up the code a lot :P

You can download the original shader here.

Original Shader
Copy to clipboard
// transform object vertices to world-space: // world_matrix float4x4 gWorldXf : World; // transform object normals, tangents, & binormals to world-space: // inverse_transpose_world_matrix float4x4 gWorldITXf : WorldInverseTranspose; // transform object vertices to view space and project them in perspective: // worldviewproj_matrix float4x4 gWvpXf : WorldViewProjection; // provide tranform from "view" or "eye" coords back to world-space: // inverse_view_matrix float4x4 gViewIXf : ViewInverse; // color and depth used for full-screen clears float4 gClearColor = {0,0,0,0}; float gClearDepth = 1.0; /************* TWEAKABLES **************/ float gInflate = 0.06; float3 gGlowColor = {1.0f, 0.9f, 0.3f}; float gGlowExpon = 1.3; /////////////////////////////////// /* data from application vertex buffer */ struct appdata { float3 Position : POSITION; float4 UV : TEXCOORD0; float4 Normal : NORMAL; float4 Tangent : TANGENT0; float4 Binormal : BINORMAL0; }; /* data passed from vertex shader to pixel shader */ struct gloVertOut { float4 HPosition : POSITION; float3 WorldNormal : TEXCOORD0; float3 WorldView : TEXCOORD1; }; /*********** vertex shader ******/ gloVertOut gloBalloon_VS(appdata IN, uniform float Inflate, uniform float4x4 WorldITXf, // our four standard "untweakable" xforms uniform float4x4 WorldXf, uniform float4x4 ViewIXf, uniform float4x4 WvpXf ) { gloVertOut OUT = (gloVertOut)0; OUT.WorldNormal = mul(WorldITXf,IN.Normal).xyz; float4 Po = float4(IN.Position.xyz,1); Po += (Inflate*normalize(float4(IN.Normal.xyz,0))); // the balloon effect float4 Pw = mul(WorldXf,Po); OUT.WorldView = normalize(float3(ViewIXf[0].w,ViewIXf[1].w,ViewIXf[2].w) - Pw.xyz); OUT.HPosition = mul(WvpXf,Po); return OUT; } /********* pixel shaders ********/ float4 gloBalloon_PS(gloVertOut IN, uniform float3 GlowColor, uniform float GlowExpon ) : COLOR { float3 Nn = normalize(IN.WorldNormal); float3 Vn = normalize(IN.WorldView); float edge = 1.0 - dot(Nn,Vn); edge = pow(edge,GlowExpon); float3 result = edge * GlowColor.rgb; return float4(result,edge); } /////////////////////////////////////// /// TECHNIQUES //////////////////////// /////////////////////////////////////// technique Main { pass GlowPass { VertexProgram = compile vp40 gloBalloon_VS(gInflate,gWorldITXf,gWorldXf, gViewIXf,gWvpXf); DepthTestEnable = true; DepthMask = true; BlendEnable = true; BlendFunc = int2(SrcAlpha,OneMinusSrcAlpha); CullFaceEnable = true; DepthFunc = LEqual; FragmentProgram = compile fp40 gloBalloon_PS(gGlowColor,gGlowExpon); } }</pre>

Then I made three files, vs_glowBalloon.cg, ps_glowBalloon.cg, and glowBalloon.material. We need to split up this cgfx file into those three.

Also because I don't know how to use structs I just removed them and replaced the structs with the arguments the shader needed.

vs_glowBalloon.cg
Copy to clipboard
void main(float3 Position : POSITION, float4 Normal : NORMAL, uniform float Inflate, uniform float4x4 WorldITXf, // our four standard "untweakable" xforms uniform float4x4 WorldXf, uniform float4x4 ViewIXf, uniform float4x4 WvpXf, out float4 HPosition : POSITION, out float3 WorldNormal : TEXCOORD0, out float3 WorldView : TEXCOORD1 ) { WorldNormal = mul(WorldITXf, Normal).xyz; float4 Po = float4(Position.xyz, 1); Po += (Inflate * normalize(float4(Normal.xyz, 0))) * Normal; // the balloon effect float4 Pw = mul(WorldXf, Po); WorldView = normalize(float3(ViewIXf[0].w, ViewIXf[1].w, ViewIXf[2].w) - Pw.xyz); HPosition = mul(WvpXf, Po); }

ps_glowBalloon.cg
Copy to clipboard
float4 main(float3 WorldNormal : TEXCOORD0, float3 WorldView : TEXCOORD1, uniform float3 GlowColor, uniform float GlowExpon ) : COLOR { float3 Nn = normalize(WorldNormal); float3 Vn = normalize(WorldView); float edge = 1.0 - dot(Nn, Vn); edge = pow(edge, GlowExpon); float3 result = edge * GlowColor.rgb; return float4(result, edge); }


There, that wasn't too hard! So now just comes the material.

We need to specify the fragment/vertex programs and tell ogre they exist, along with giving them their arguments.
This is where the manual comes in handy ;D
Then we just have to write the material, reference the shaders, and try to make our material match the one at the bottom of the original shader.

glowBalloon.material
Copy to clipboard
vertex_program glowBalloon_vs cg { source vs_glowBalloon.cg entry_point main profiles vs_2_0 arbvp1 vs_2_x vs_3_0 vp40 default_params { param_named Inflate float 0.06 param_named_auto WorldITXf inverse_transpose_world_matrix param_named_auto WorldXf world_matrix param_named_auto ViewIXf inverse_view_matrix param_named_auto WvpXf worldviewproj_matrix } } fragment_program glowBalloon_ps cg { source ps_glowBalloon.cg entry_point main profiles ps_2_0 arbfp1 ps_2_x ps_3_0 ps_3_x fp40 default_params { param_named GlowColor float3 1.0 1.0 1.0 param_named GlowExpon float 1.3 } } material cg/balloon_glow { technique { pass { scene_blend src_alpha one_minus_src_alpha depth_check on depth_func less_equal lighting off vertex_program_ref glowBalloon_vs { param_named Inflate float 0.1 } fragment_program_ref glowBalloon_ps { param_named GlowColor float3 0.0 1.0 0.0 param_named GlowExpon float 1.3 } } } }


Hooray!

- Pyritie


Alias: GlowBalloon_CG_Shader