Star glow/bloom post processing shader (for cheap sparkle particles)

Im looking at creating something that looks like a massive array of LEDs on screen on iOS, but I understand there can be fillrate issues with lots of overlapping transparent particles. Id quite like the LEDs to have some glow around them, along with some trapcode starglow-like streaks:

So I thought rather than waste 80% of the fillrate on the overlapping glows, I could simply render coloured disc particles and do it in post. Is this possible to do with a shader, using a combination of alpha and brightness to pick out the particles?

The Pro Assets Bloom and Flare image effect seems like a step in the right direction, but only has anamorphic horizontal streaks for the flares (which move around the screen). Has anyone seen a shader similar to this, or know if theres a name I’m not using when searching (tried star glow, bloom streaks, bloom flare etc.). I’m a 100% beginner to shaders, so I cant start from scratch, but could possibly learn to adapt something similar.

You must put some squares or circles on your screen with distinct colors with another preferably black backdrop (can be done in the post process shader as well) and then just add blur in a star shape with bloom on the center. That will do.

If you want an easy start;
I have smiliar shaders in my shader pack which can be found in the asset store.
Although none of them do exactly what you want but all of them are the good starting points for it. All you have to do is change the blur shape.

EDIT: Infact, i will use this idea and add it to my pack. Would you mind?

doing this would be perfectly fine in performance on iOS if you render it to a half or quarter res texture, and scale it up rendering to the main buffer. It should still look mostly the same I think. This will save up to 4 times your fill rate :slight_smile:

Another concept is:

  1. the little glowing balls are normal particles, or textured quads

  2. all the diagonal long strips are an opaque mesh, with gradient texture. All these opaque meshes overlap and are drawn to a texture

  3. the texture is drawn back to the display as a large quad with add blend

This will keep the high res and mostly look identical but represent filling the screen twice roughly - which is still doable at 60fps on most iOS hardware. There isn’t much of a fill rate hit with this method.

Faking it and approximations are really the best way to go here :slight_smile:

Not at all. I’ve found an HLSL shader that might be the right direction here http://developer.download.nvidia.com/shaderlibrary/webpages/hlsl_shaders.html#post_starFilter although the sample image isnt great so I’m not sure its right.

For my purposes, it would have been great to have an existing shader with settings like streak numbers (2 (horiz/vert), 4, 8 would seem to be easy. Not sure about 3, 5, 6 etc), threshold, streak length, streak quality, maybe some falloff control, intensity, and pre/post blur/glow (though that could just be another shader).

Hippocoder - Thanks, yeah I was thinking about using that blurst article on off-screen particles if I got the time to implement it. Seems like a good match for the retina displays because most scenes dont really need that pixel density for soft glows etc.

EDIT - heres a version of the star filter shader for CoreImage, no idea if that helps: http://machinesdontcare.wordpress.com/2009/05/26/nvidia-post-star-filter/

EDITEDITEDIT: Theres a great looking implementation here on page 17: http://developer.amd.com/media/gpu_assets/Oat-ScenePostprocessing.pdf ‘Kawase’s Light Streak Filter’

I havent gotten to the starglow yet, but heres a massively flawed script that does offscreen particles and bloom on iOS, duct-taped together from mobilebloom and blurst’s example. It totally ignores depth for my purposes, but it should be possible to hack that back in.

Use the mobilebloom material in the bloom slot, and a fast additive/soft additive shader in the postblend slot. The particles should be tagged as layer 15, and the main camera set to ignore layer 15. There may be an extra unnecessary step at the end there because I was using it for AR and didnt want the video bloomed too. The bloom script doesnt need to be inline either, but I`m midway through tracking down a bug that seems to come from moving too many rendertextures around.

#pragma strict

 
function Awake () {
this.camera.depthTextureMode = DepthTextureMode.None;
}


public var intensity : float = 0.7f;
public var threshhold : float = 0.75f;
public var blurWidth : float = 1.0f;
public var downsampleset : int = 2; 
public var postdownsampleFactor : int = 2; 
public var extraBlurry : boolean = false;
public var postblend : Shader;
// image effects materials for internal use

public var bloomMaterial : Material = null;
private var blendMaterial:Material = null;
blendMaterial = new Material(postblend);

private var supported : boolean = true;
private var tempRtA : RenderTexture = null;
private var tempRtB : RenderTexture = null;
private var particlesRT : RenderTexture = null;
private var ParticlePost : RenderTexture = null;



function CreateBuffers () {			
	if (!tempRtA) {
		tempRtA = new RenderTexture (Screen.width / 4, Screen.height / 4, 0);
		tempRtA.hideFlags = HideFlags.DontSave;		
	}
	if (!tempRtB) {
		tempRtB = new RenderTexture (Screen.width / 4, Screen.height / 4, 0);	
		tempRtB.hideFlags = HideFlags.DontSave;
	}
		if (!particlesRT) {
		particlesRT = new RenderTexture (Screen.width / downsampleset, Screen.height / downsampleset, 0);	
		particlesRT.hideFlags = HideFlags.DontSave;
	}
		if (!ParticlePost) {
		ParticlePost = new RenderTexture (Screen.width / postdownsampleFactor, Screen.height / postdownsampleFactor, 0);	
		ParticlePost.hideFlags = HideFlags.DontSave;
	}
}

function OnDisable () {
	if (tempRtA) {
		DestroyImmediate (tempRtA);
		tempRtA = null;
	}	
	if (tempRtB) {
		DestroyImmediate (tempRtB);
		tempRtB = null;
	}	
		if (particlesRT) {
		DestroyImmediate (particlesRT);
		particlesRT = null;
	}	
	if (ParticlePost) {
		DestroyImmediate (ParticlePost);
		ParticlePost = null;
	}
}




function OnRenderImage (source :RenderTexture, destination:RenderTexture) {
CreateBuffers ();


//setup camera
var ppCamera:Camera = GetPPCamera();
ppCamera.CopyFrom(this.camera);
ppCamera.depthTextureMode = DepthTextureMode.None;
ppCamera.cullingMask |= (1 << 15);//set particle/bloom layer
ppCamera.targetTexture = particlesRT;
ppCamera.clearFlags = CameraClearFlags.SolidColor;
ppCamera.backgroundColor = Color.black;

ppCamera.Render();

	// prepare data
	
	bloomMaterial.SetVector ("_Parameter", Vector4 (0.0f,  0.0f, threshhold, intensity / (1.0f - threshhold)));	
	
	// ds  blur
	
	var oneOverW : float = 1.0f / (particlesRT.width * 1.0f);
	var oneOverH : float = 1.0f / (particlesRT.height * 1.0f);

	bloomMaterial.SetVector("_OffsetsA", Vector4(1.5f*oneOverW,1.5f*oneOverH,-1.5f*oneOverW,1.5f*oneOverH));	
	bloomMaterial.SetVector("_OffsetsB", Vector4(-1.5f*oneOverW,-1.5f*oneOverH,1.5f*oneOverW,-1.5f*oneOverH));	

	Graphics.Blit (particlesRT, tempRtB, bloomMaterial, 1);
	
	oneOverW *= 4.0f * blurWidth;
	oneOverH *= 4.0f * blurWidth;
	
	bloomMaterial.SetVector("_OffsetsA", Vector4(1.5f*oneOverW,0.0f,-1.5f*oneOverW,0.0f));	
	bloomMaterial.SetVector("_OffsetsB", Vector4(0.5f*oneOverW,0.0f,-0.5f*oneOverW,0.0f));	
	Graphics.Blit (tempRtB, tempRtA, bloomMaterial, 2);
	
	bloomMaterial.SetVector("_OffsetsA", Vector4(0.0f,1.5f*oneOverH,0.0f,-1.5f*oneOverH));	
	bloomMaterial.SetVector("_OffsetsB", Vector4(0.0f,0.5f*oneOverH,0.0f,-0.5f*oneOverH));	
	Graphics.Blit (tempRtA, tempRtB, bloomMaterial, 2);
	
	if(extraBlurry) {
		bloomMaterial.SetVector("_OffsetsA", Vector4(1.5f*oneOverW,0.0f,-1.5f*oneOverW,0.0f));	
		bloomMaterial.SetVector("_OffsetsB", Vector4(0.5f*oneOverW,0.0f,-0.5f*oneOverW,0.0f));	
		Graphics.Blit (tempRtB, tempRtA, bloomMaterial, 2);
		
		bloomMaterial.SetVector("_OffsetsA", Vector4(0.0f,1.5f*oneOverH,0.0f,-1.5f*oneOverH));	
		bloomMaterial.SetVector("_OffsetsB", Vector4(0.0f,0.5f*oneOverH,0.0f,-0.5f*oneOverH));	
		Graphics.Blit (tempRtA, tempRtB, bloomMaterial, 2);		
	}
	
	// bloomMaterial
	
	bloomMaterial.SetTexture ("_Bloom", tempRtB);
	Graphics.Blit (particlesRT, ParticlePost, bloomMaterial, 0);

//Add particles over this camera's view
Graphics.Blit(ParticlePost, source, blendMaterial); 

//final composite
Graphics.Blit(source, destination);


}


private static var ppCameraGO:GameObject;
static function GetPPCamera():Camera
{
   // Create the shader camera if it doesn’t exist yet
   if(!ppCameraGO) {
      ppCameraGO = new GameObject("Post Processing Camera", Camera);
      ppCameraGO.camera.enabled = false;
      ppCameraGO.hideFlags = HideFlags.HideAndDontSave;
   }

   return ppCameraGO.camera;
}

For anyone that comes along Kawase’s Light Streak Filter is what you’re looking for. I’ve implemented it here, have a look:

Thanks for the nice screenshot! Now, where did you post your source code :smile:

Good link, thanks!

I don’t consider myself a total beginner, but what do I do with the code?
I thought it was C#, but there is no float3, so I’m guessing it’s shader language? If I assemble the shader, what do I do with it? I was hoping it would work like the built-in glow, just put it on the camera…
So, please forgive, if this is a stupid question, but where do I paste that code and how do I apply it to my scene?

Learn shaders (yes you’re a total beginner at shaders). - see Unity - Manual: Shaders core concepts and Cg Programming/Unity/Introduction - Wikibooks, open books for an open world

At shaders, yes total noob. Just graphics and Javascript so far. Thanks, I’ll look into it.

1 Like

OK, I don’t have time to learn yet another scripting language, and I can’t find this for Unity anywhere. Even in the shop I did not find anything comparable.
So how about this: You send me the Unity shader, ready to be put onto a diamond, and I’ll send you $20, sounds good?
I mean, you probably have this lying around on your computer anyways, right?

Hi!

I just came across here and I would like to download an asset to generate the light effect from the first post.
Thanks!