Inner glow effect for sprites

Started by
1 comment, last by Ashaman73 14 years, 2 months ago
Hallo, I was wondering if someone could give me any pointers to how I can recreate the inner glow effect you find in Photoshop using a pixel shader on a 2d sprite? Regards,
Advertisement
Don't know precisely what photoshop does, but isn't it just blurring with the background, except that the background itself won't get blurred? Ifso...

<step 1, background info>
1- Make a RGB background render target / FBO
2- On that, render the scene with a (simple) background color. The background color is used to blur into the sprites. Could be simply white, but also a skybox and/or flares from lights.
3- Render the rest of the geometry on top. However, render it black, unless it is an emmissive surface (neon letters for example). That means you don't have to use texturing or lighting in this pass. Making it fast.
4- Render the (transparent) sprites on top. Again, render them black unless they have emmissive pixels.


This result will be stored into a texture you can use later again. You can do this on a relative small resolution to win some speed. Half screen size for example.

<step 2, bloom layer>
1- Create another background texture / render target / FBO to render on. Again, use a smaller resolution. Blurring is relative heavy, so the less pixels, the better. Besides, using smaller textures also allows to create larger blurs more easier.
2- Give it a black bacground color
3- Render the sprites with your "glow into" shader applied on them. This shader will make use of the background image you generated in step 1, so pass that texture as one of the shader parameters.
3- Within the sprites, you'll make a blurred color with the background info. Check out examples howto do a Guassian blur. Here is some basic code:
// "OriginalUV" is not the sprite quad texcoord, but the screen position.// You want to grab the pixels behind the sprite.sumColor = tex2D( backGroundImage, originalUV  ); // center pixelsumCount = 1;for x= -4 to +4  for y=-4 to +4    // Taking 64 samples  {     offsetUV = originalUV + half2(x * 1/screenW , y * 1/screenH);     sample = tex2D( backGroundImage, offsetUV );     sumColor += sample.rgb ( * gaussian Kernel[x,y] eventually )     ++sumCount  }average.rgb = sumColor.rgb / sumCount.xxx;out.color.rgb = average.rgb;// IMPORTANT, transparent pixels of the sprite should result into black, // otherwise the blur will move outside the sprite. Just put alpha on// 0 to limit or kill the contribtion:out.color.a = tex2D( spriteTexture, quadTexcoords.xy ).a;// If you have modern hardware, you can use branching ( IF (sprite.alpha < 0.01)// to skip the entire loop above for transparent pixels...

Notice that there are faster ways to do a blur (doing it in 2 passes for example). It's still fairly cheap though, as you only blur inside sprite rectangles, not on the entire screen.


Now you have a black texture where the edges of sprites are gloomy. Eventually you want to add a multiplier to the shader above to increase/decrease the influence.


< final step >
1- Render the scene as usual, including your sprites rendered normally.
2- Enable additive blending
3- Render a screenfilling quad with the blurry result from step 2 applied on it. Bright background colors (skybox, flares, neon, maybe highly litten surfaces, maybe other emmissive sprites) are now blurred into the sprites.


Probably there are ways to optimize this further, even with less passes maybe. But I hope you get the point :)

Rick

[Edited by - spek on February 18, 2010 7:00:03 AM]
Spek's way of doing it looks like it would work.

Here's an other one-pass way of doing it:
Blur the alpha-channel , invert it and mask it by the alpha value of the center pixel, here's some code derived from Speks solution :)

center = tex2D( backGroundImage, originalUV  ); // center pixelsumColor = vec3(0);sumCount = 1;for x= -4 to +4  for y=-4 to +4    // Taking 64 samples  {     offsetUV = originalUV + half2(x * 1/screenW , y * 1/screenH);     sample = tex2D( backGroundImage, offsetUV );     sumColor += sample ( * gaussian Kernel[x,y] eventually )     ++sumCount  }// take invert of averageaverage.a = 1.0 - (sumColor.a / sumCount.x);// add it to center color out.color.rgb = center.rgb + average.aaa * GLOW_COLOR.rgb;// write alpha to mask or blend the spriteout.color.a = center.a;


This should work in one pass, but Speks solution might be faster if you devide the blur into two passes.

This topic is closed to new replies.

Advertisement