I have been working on a very very basic bloom shader. The basic idea is that before rendering a frame, I will render it onto a RenderTarget. Then, I render the RenderTarget onto the screen with the bloom shader (with Point filtering because it’s a pixel art game).
However, I can’t figure out why it produces a diagonal (from bottom-left to top-right) seam on the entire screen like this:
In the pixel shader, I find the HSV (similar to HSL) of surrounding pixels and add the Value component of HSV (the V is also multiplied by some weight based on distance) to the current pixel’s Value component. This will brighten the current pixel based on how bright its neighbors are.
Below is my pixel shader. Note that the methods that convert between RGB and HSV are tested and correct. Also, the bloom effect itself is working properly, the only issue is the seam from the bottom-left corner to the top-right corner of the screen. I know there are better ways to implement bloom shaders like with Gaussian Blur, but I want to focus on this simple one for now.
float strength; // passed in from C#
float2 textureSize; // passed in from C#
Texture2D SpriteTexture;
sampler2D SpriteTextureSampler = sampler_state
{
Texture = <SpriteTexture>;
};
// SOME UNRELATED CODE HERE............
float4 MainPS(VertexShaderOutput input) : COLOR
{
float2 coords = input.TextureCoordinates;
float4 color = tex2D(SpriteTextureSampler, coords);
float3 hsv = RGBtoHSV(color.rgb); // get HSV of this pixel
float2 offset = 1.0f / textureSize; // this is how big a pixel is in UV
int neighbors = 3; // how many neighbors in each direction to sample
for (int i = -neighbors; i <= neighbors; i++)
{
for (int j = -neighbors; j <= neighbors; j++)
{
// sample with the given offset
if (i == 0 && j == 0)
continue;
float2 neighborCoords = coords + float2(offset.x * i, offset.y * j);// get neighbor position in UV
float4 neighborColor = tex2D(SpriteTextureSampler, neighborCoords);// get neighbor RGB
float3 neighborHSV = RGBtoHSV(neighborColor.rgb);// get neighbor HSV
// calculate weight based on the distance to neighbor (closer = more weight)
float weight = (sqrt(neighbors * neighbors * 2) - length(float2(i, j))) * strength / sqrt(neighbors * neighbors * 2);
// add the neighbor's influence to the current pixel's V component, which can brighten this pixel
hsv.z += neighborHSV.z * weight;
}
}
color = float4(HSVtoRGB(hsv), color.a);
return color * input.Color;
}
// SOME UNRELATED CODE HERE..............
After some testing, I found that if I increase neighbors
, it will make the seam more visible. Also, if I set strength
to 0
in C#, the seam will disappear (but I don’t want to set strength
to 0
because that would get rid of the bloom effect entirely).