Unexpected Results in HLSL

Started by
0 comments, last by Promethium 12 years, 6 months ago
So, I've been trying to pick up HLSL. I have a very basic understanding of it so far, and I was trying to apply what I had learned to create a blur effect. Seems like something that shouldn't be too complicated, but I'm having some very unexpected results. Instead of blurring, it looks as if a semi-transparent picture of the screen has been flipped horizontally and then superimposed over the original picture. In other words, The screen seems to mirror itself right at the center line. It will probably be easy for you gurus to see what's wrong as the code is not very long...here's my shader code:

//------------------------------ TEXTURE PROPERTIES ----------------------------
// This is the texture that SpriteBatch will try to set before drawing
texture ScreenTexture;
float extent = 3;

// The Whole Texture
Texture xColoredTexture;

sampler ColoredTextureSampler = sampler_state
{ texture = <xColoredTexture> ;
magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR;
AddressU = mirror; AddressV = mirror;};

//------------------------ PIXEL SHADER ----------------------------------------
// This pixel shader will simply look up the color of the texture at the
// requested point
float4 PixelShaderFunction(float2 TextureCoordinate : TEXCOORD0) : COLOR0
{
float4 color = tex2D(ColoredTextureSampler, TextureCoordinate);
TextureCoordinate.x += 1;
float4 colorR = tex2D(ColoredTextureSampler, TextureCoordinate);
TextureCoordinate.y -= 1;
float4 colorUPR = tex2D(ColoredTextureSampler, TextureCoordinate);
TextureCoordinate.x -= 1;
float4 colorU = tex2D(ColoredTextureSampler, TextureCoordinate);
TextureCoordinate.x -= 1;
float4 colorUL = tex2D(ColoredTextureSampler, TextureCoordinate);
TextureCoordinate.y += 1;
float4 colorL = tex2D(ColoredTextureSampler, TextureCoordinate);
TextureCoordinate.y += 1;
float4 colorDL = tex2D(ColoredTextureSampler, TextureCoordinate);
TextureCoordinate.x += 1;
float4 colorD = tex2D(ColoredTextureSampler, TextureCoordinate);
TextureCoordinate.x += 1;
float4 colorDR = tex2D(ColoredTextureSampler, TextureCoordinate);

float r = (color.r + colorR.r + colorUPR.r + colorU.r + colorUL.r + colorL.r + colorDL.r + colorD.r + colorDR.r)/9;
float g = (color.g + colorR.g + colorUPR.g + colorU.g + colorUL.g + colorL.g + colorDL.g + colorD.g + colorDR.g)/9;
float b = (color.b + colorR.b + colorUPR.b + colorU.b + colorUL.b + colorL.b + colorDL.b + colorD.b + colorDR.b)/9;

color.r = r;
color.g = g;
color.b = b;
//float value = (color.r + color.g + color.b) / 3;
//color.r = value;
//color.g = value;
//color.b = value;

return color;

}

//-------------------------- TECHNIQUES ----------------------------------------
// This technique is pretty simple - only one pass, and only a pixel shader
technique Plain
{
pass Pass1
{
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}

I understand that this isn't an ideal way to get a blur (since this function will blur only to a specific extent, using a specific kernel), but I wanted to throw something together quickly just to test it (which turned out to be a good idea since it doesn't work!) The Color floats in PixelShaderFunction were supposed to retrieve the color properties of each pixel surrounding the current pixel being processed. I then average each color value and set the new value to the current pixel. Why would this have such strange results? It seems like a pretty straightforward way to go about things. Any ideas?

P.S. I don't actually ever use the ScreenTexture global. I just set the ColoredTextureSampler to the picture that I'm wanting to get data from (from XNA of course), and I set this effect through the SpriteBatch.Begin() method.

EDIT: I've played with it some, and I remember reading somewhere that texture coordinates are recorded in terms of a number between 0 and 1 that represents a percent width, percent height. So, I tried adding/subtracting a variable xInterval which equals 1.0f / image.width (same for yInterval except image.height), and that fixed the mirroring effect...but now I can't even tell a difference between the original picture and the affected one...maybe the effect is just too subtle if I just go one pixel out. I also tried multiplying the interval by 10 on each...thinking this would at least produce a difference between the original picture and affected one, but still nothing. Weird...
Advertisement
Your UV coordinate ([color="#1C2837"]TextureCoordinate) calculations are wrong. UV's go from (0,0) in the upper left corner of the texture to (1,1) in the bottom right corner. So when you add 1 to [color="#1C2837"]TextureCoordinate.x you jump a whole texture width! Instead you want to add 1/texture-width. You should of course calculate this once on the CPU and transfer it to the GPU in a uniform.

These lines:
float r = (color.r + colorR.r + colorUPR.r + colorU.r + colorUL.r + colorL.r + colorDL.r + colorD.r + colorDR.r)/9;
float g = (color.g + colorR.g + colorUPR.g + colorU.g + colorUL.g + colorL.g + colorDL.g + colorD.g + colorDR.g)/9;
float b = (color.b + colorR.b + colorUPR.b + colorU.b + colorUL.b + colorL.b + colorDL.b + colorD.b + colorDR.b)/9;

They are not wrong, but a bit redundant and verbose. The GPU is a vector processor that likes to work on a full float4 in each calculation, so you can reduce all of that to
color.rgb = (color.rgb + colorR.rgb + colorUPR.rgb + colorU.rgb + colorUL.rgb + colorL.rgb + colorDL.rgb + colorD.rgb + colorDR.rgb) / 9
and get the same result. If you also want to blur the alpha you can leave out the .rgba altogether.

This topic is closed to new replies.

Advertisement