6
\$\begingroup\$

I'm making a neon style game where everything is glowing but the glow I have is kinda small and I want to know if there's an efficient way to increase the size of it other than increasing the pixel sample iterations.

Right now I have something like this:

float4 glowColor = tex2D(glowSampler, uvPixel);

//Makes the inital lines brighter/closer to white
if (glowColor.r != 0 || glowColor.g != 0 || glowColor.b != 0)
{
    glowColor += 0.5;
}

//Loops over the weights and offsets and samples from the pixels based on those numbers
for (int i = 0; i < 20; i++)
{
    glowColor += tex2D(glowSampler, uvPixel + glowOffsets[i] + 0.0018) * glowWeights[i];
}

finalColor += glowColor;

for the offsets it moves up, down, left and right (5 times each so it loops over 20 times) and the weights just lower the glow amount the further away it gets.

The method I was using before to increase it was to increase the number of iterations from 20 to 40 and to increase the size of the offset/weight array but my computer started to have FPS drops when I was doing this so I was wondering how can I make the glow bigger/more vibrant without making it so CPU/Gcard intensive?

\$\endgroup\$

2 Answers 2

5
\$\begingroup\$

There are two common approaches, both of which can be used together or independently. The first assumes you have some kind of "bright pass" that renders the "glow" texture. Because blurring inherently produces low-frequency results, you should be able to reduce the resolution of this pass, so the same number of samples cover a larger fraction of the screen area.

The second approach is to take advantage of the fact that blur is typically separable. You can therefore use a two-pass approach, blurring in only one direction in the first pass (e.g. horizontal), then in another in the second pass (vertical). This reduces the total number of samples from N^2 to 2N, though there is some overhead for multi-pass in general.

There is a third approach, but it does not seem like it would work for your case (since it looks like you're doing colored blurs). This option involves using the Gather method to get 4 samples from one call, reducing the total number of samples required by a factor of 4. This only works for single-channel color, however.

\$\endgroup\$
3
  • \$\begingroup\$ The first approach sounds quite nice, what exactly would I have to do? Just lower the size/resolution of the initial render texture that gets passed into the glow shader? My math isn't that great so I'm not sure how big a difference N^2 to 2N would make, but if I separated it into multiple passes (including the overhead of a multi-pass shader) would it make a big difference or would it only improve it a tiny bit? \$\endgroup\$ Oct 22, 2013 at 14:12
  • 1
    \$\begingroup\$ There's a tutorial here: gamerendering.com/2008/10/11/gaussian-blur-filter-shader \$\endgroup\$ Oct 22, 2013 at 14:40
  • \$\begingroup\$ You can also use bilinear filtering hardware to do some of the work. Instead of taking 4 texture samples from 4 adjacent texels and multiplying each by a weight when added, you can take 1 texture sample from a position carefully offset between them, so that the hardware filtering blends them in the desired weighted combination and returns it in that single result. This can halve the number of taps you need in each pass for a separable blur, or quarter the taps you need in a non-separated blur. \$\endgroup\$
    – DMGregory
    May 13, 2022 at 12:31
1
\$\begingroup\$
if (glowColor.r != 0 || glowColor.g != 0 || glowColor.b != 0)
{
    glowColor += 0.5;
}

could be written as

>  if (any(glowColor.rgb))  
>  {
>      glowColor += 0.5;  
>  }

I did't try but this also could work:

glowColor += 0.5 * sign(any(glowColor.rgb));
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .