MULTIMEDIA

Programming with DirectX : Additional Texture Mapping - Image Filters

2/5/2011 5:01:28 PM
An image filter is an algorithm that is executed to convert a picture from its original input to some type of output, which is dependent on the algorithm itself. Examples of some image filters are color inversion filters, black-and-white (luminance) filters, sepia filters, edge detection filters, blur filters, and so forth.

In this section we will look at a few simple image filters and apply them to textures being rendered on square surfaces to keep the code short and simple.

Color Inversion

Color inversion is a simple effect to create when it comes to image filters. To perform this effect we only have to use 1 minus the color in the pixel shader. This makes colors that are 1 equal to 0 and colors that are 0 equal to 1. In other words, it flips the colors around, so dark becomes light and light becomes dark.

The effect shader file from the demo is shown in Listing 1. Figure 1 shows a screenshot of the effect.

Listing 1. Color Inversion Demo’s Effect Shader File
/*
Color Inversion Filter Demo's HLSL Shader
Ultimate Game Programming with DirectX 2nd Edition
Created by Allen Sherrod
*/

Texture2D decal;

SamplerState DecalSampler
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};

cbuffer cbChangesEveryFrame
{
matrix World;
matrix View;
};

cbuffer cbChangeOnResize
{
matrix Projection;
};

struct VS_INPUT
{
float4 Pos : POSITION;
float2 Tex : TEXCOORD;
};

struct PS_INPUT
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD0;
};

PS_INPUT VS(VS_INPUT input)
{
PS_INPUT output = (PS_INPUT)0;

output.Pos = mul(input.Pos, World);
output.Pos = mul(output.Pos, View);
output.Pos = mul(output.Pos, Projection);

output.Tex = input.Tex;

return output;
}

float4 PS(PS_INPUT input) : SV_Target
{
return 1 - decal.Sample(DecalSampler, input.Tex);
}
technique10 ColorInversion
{
pass P0
{
SetVertexShader(CompileShader(vs_4_0, VS()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0, PS()));
}
}

Figure 1. Screenshot from the Color Inversion demo.

Luminance Filter

The algorithm for the luminance filter works by taking each color in the pixel shader and multiplying each component by the luminance constant. You then add the result of each multiplied component together to get the value that will act as the grayscale pixel output. The luminance constant is 0.30 for the red, 0.59 for the green, and 0.11 for the blue components. Multiplying the color’s red, green, and blue components by this luminance constant and then adding the results of all components will create a result that appears black and white for all pixels. The operations are shown as follows, where color is the original pixel color and lum is the luminance constant (0.30, 0.59, 0.11).

Luminance = color.red * lum.red + color.green * lum.green + color.blue * lum.blue

This operation is essentially the dot product of two vectors, or in this case two colors. You can use the HLSL dot() function to perform this operation, which will be discussed in more detail in the next chapter for vectors. For now, know that the dot() function takes each component from the two vectors (color and the luminance constant in this example) and multiplies them together and adds up the results. The resulting value is used for the output color. The Luminance demo’s effect shader file is shown in Listing 2. Figure 2 shows a screenshot of the demo in action.

Listing 2. The Luminance Demo’s Effect Shader File
/*
Luminance Filter
Ultimate Game Programming with DirectX 2nd Edition
Created by Allen Sherrod
*/

Texture2D decal;

SamplerState DecalSampler
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};

cbuffer cbChangesEveryFrame
{
matrix World;
matrix View;
};

cbuffer cbChangeOnResize
{
matrix Projection;
};

struct VS_INPUT
{
float4 Pos : POSITION;
float2 Tex : TEXCOORD;
};

struct PS_INPUT
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD0;
};

PS_INPUT VS(VS_INPUT input)
{
PS_INPUT output = (PS_INPUT)0;
output.Pos = mul(input.Pos, World);
output.Pos = mul(output.Pos, View);
output.Pos = mul(output.Pos, Projection);

output.Tex = input.Tex;

return output;
}

float4 PS(PS_INPUT input) : SV_Target
{
float3 lumConst = float3(0.30, 0.59, 0.11);

float3 color = decal.Sample(DecalSampler, input.Tex);
float dp = dot(color, lumConst);

return float4(dp, dp, dp, 1);
}


technique10 LuminanceFilter
{
pass P0
{
SetVertexShader(CompileShader(vs_4_0, VS()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0, PS()));
}
}

The luminance filter is also known as the black-and-white transfer function.


Figure 2. A screenshot from the Luminance demo.

Sepia Tone Filter

The sepia tone effect is used to color a black-and-white image with a brownish tone to give it the appearance of and old photograph. It does this by taking the original color and a brown tone, and using the two to color a black-and-white version of the image to create the effect. As the description implies, the sepia tone builds off of the luminance filter.

The sepia tone filter works in the following steps.

1.
Convert the image to black and white.

2.
Use the luminance (black-and-white) value as a percent between a light and dark set of colors to create the sepia constant, where 0% (0.0) means we use the dark color, 100% (1.0) means we use the light color, and any percentage between 0% and 100% will be a color value between the light and dark colors.

3.
Take the original color and the luminance color and find a color that is halfway between the two. Let’s call this the half color.

4.
Use the half color and the sepia constant and find a color that is halfway between those two. This will be the output color.

In HLSL you can find a color that is between two colors by using the lerp() function. The lerp() function takes as parameters the first vector (or color in this demo, which is represented by a vector; i.e., they’re the same thing from a structure point of view), the second vector, and a percentage to interpolate between the two. Finding a color between two colors is another way of mixing colors because the result will be a blend of the two colors. When you find a color that is halfway between two other colors, it is like you are equally mixing the colors together.

The term lerp stands for linear interpolation. For a simple example, let’s say we are interpolating between the values 0 and 100. The percentage is used to find a value between these two, where a percentage of 0.0 will return 0, and a percent of 1.0 will return 100. So if the percentage is 0.65, then 65 will be returned since 65% into the range of 0 and 100 is 65. The lerp() function does this operation, but on two vectors to obtain a vector that is some percentage between the two parameters. Therefore, to find a color between two colors using lerp(), you just specify the two colors and a percentage between the two for which you want to look. Since we are using colors, the result will be a blend between the two.

The sepia tone effect is shown in Listing 3 in the demo’s shader file. This demo builds off of the Luminance demo and adds a few extra lines of code to the pixel shader. Figure 3 shows a screenshot of the demo. We recommend that you run the demo applications to see the results in color to be able to fully appreciate the differences between each image filter.

Listing 3. The Sepia Demo’s HLSL Effect Shader File
/*
Sepia Filter Demo's HLSL Shader
Ultimate Game Programming with DirectX 2nd Edition
Created by Allen Sherrod
*/

Texture2D decal;

SamplerState DecalSampler
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};

cbuffer cbChangesEveryFrame
{
matrix World;
matrix View;
};

cbuffer cbChangeOnResize
{
matrix Projection;
};

struct VS_INPUT
{
float4 Pos : POSITION;
float2 Tex : TEXCOORD;
};

struct PS_INPUT
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD0;
};

PS_INPUT VS(VS_INPUT input)
{
PS_INPUT output = (PS_INPUT)0;

output.Pos = mul(input.Pos, World);
output.Pos = mul(output.Pos, View);
output.Pos = mul(output.Pos, Projection);

output.Tex = input.Tex;

return output;
}

float4 PS(PS_INPUT input) : SV_Target
{
float3 lumConst = float3(0.30, 0.59, 0.11);
float3 light = float3(1, 0.9, 0.5);
float3 dark = float3(0.2, 0.05, 0);

float3 color = decal.Sample(DecalSampler, input.Tex);

float luminance = dot(color, lumConst);
float3 sepia = lerp(dark, light, luminance);
float3 halfColor = lerp(color, luminance, 0.5);
float3 final = lerp(halfColor, sepia, 0.5);

return float4(final, 1);
}

technique10 SepiaFilter
{
pass P0
{
SetVertexShader(CompileShader(vs_4_0, VS()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0, PS()));
}
}

Figure 3. A screenshot from the Sepia demo.

Other  
  •  Microsoft XNA Game Studio 3.0 : Making a Game Program
  •  iPhone 3D Programming : Textures and Image Capture - Texture Compression with PVRTC
  •  iPhone 3D Programming : Textures and Image Capture - Texture Formats and Types
  •  iPhone 3D Programming : Textures and Image Capture - Fight Aliasing with Filtering
  •  iPhone 3D Programming : Textures and Image Capture - Texture Coordinates Revisited
  •  Programming with DirectX : Additional Texture Mapping - Sprites
  •  Programming with DirectX : Additional Texture Mapping - Alpha Mapping
  •  Microsoft XNA Game Studio 3.0 : Writing Your First Program (part 2) - Running the Same XNA Game on Different Devices
  •  Microsoft XNA Game Studio 3.0 : Writing Your First Program (part 1)
  •  Programming with DirectX : Shading and Surfaces - Additional Texturing Topics
  •  iPhone 3D Programming : Adding Textures to ModelViewer (part 4) - Enabling Textures with ES2::RenderingEngine
  •  iPhone 3D Programming : Adding Textures to ModelViewer (part 3) - Enabling Textures with ES1::RenderingEngine
  •  iPhone 3D Programming : Adding Textures to ModelViewer (part 2) - Generating Texture Coordinates
  •  iPhone 3D Programming : Adding Textures to ModelViewer (part 1) - Enhancing IResourceManager
  •  Programming with DirectX : Shading and Surfaces - Implementing Texture Mapping (part 2) - Multi Texture Demo
  •  Programming with DirectX : Shading and Surfaces - Implementing Texture Mapping (part 1) - 2D Texture Mapping Demo
  •  Building Out Of Browser Silverlight Applications - Using COM Interoperability and File System Access
  •  Building Out Of Browser Silverlight Applications - Controlling the Application Window
  •  iPhone 3D Programming : Adding Depth and Realism - Loading Geometry from OBJ Files
  •  iPhone 3D Programming : Adding Depth and Realism - Better Wireframes Using Polygon Offset
  •  
    Top 10
    Nikon 1 J2 With Stylish Design And Dependable Image And Video Quality
    Canon Powershot D20 - Super-Durable Waterproof Camera
    Fujifilm Finepix F800EXR – Another Excellent EXR
    Sony NEX-6 – The Best Compact Camera
    Teufel Cubycon 2 – An Excellent All-In-One For Films
    Dell S2740L - A Beautifully Crafted 27-inch IPS Monitor
    Philips 55PFL6007T With Fantastic Picture Quality
    Philips Gioco 278G4 – An Excellent 27-inch Screen
    Sony VPL-HW50ES – Sony’s Best Home Cinema Projector
    Windows Vista : Installing and Running Applications - Launching Applications
    Most View
    Bamboo Splash - Powerful Specs And Friendly Interface
    Powered By Windows (Part 2) - Toshiba Satellite U840 Series, Philips E248C3 MODA Lightframe Monitor & HP Envy Spectre 14
    MSI X79A-GD65 8D - Power without the Cost
    Canon EOS M With Wonderful Touchscreen Interface (Part 1)
    Windows Server 2003 : Building an Active Directory Structure (part 1) - The First Domain
    Personalize Your iPhone Case
    Speed ​​up browsing with a faster DNS
    Using and Configuring Public Folder Sharing
    Extending the Real-Time Communications Functionality of Exchange Server 2007 : Installing OCS 2007 (part 1)
    Google, privacy & you (Part 1)
    iPhone Application Development : Making Multivalue Choices with Pickers - Understanding Pickers
    Microsoft Surface With Windows RT - Truly A Unique Tablet
    Network Configuration & Troubleshooting (Part 1)
    Panasonic Lumix GH3 – The Fastest Touchscreen-Camera (Part 2)
    Programming Microsoft SQL Server 2005 : FOR XML Commands (part 3) - OPENXML Enhancements in SQL Server 2005
    Exchange Server 2010 : Track Exchange Performance (part 2) - Test the Performance Limitations in a Lab
    Extra Network Hardware Round-Up (Part 2) - NAS Drives, Media Center Extenders & Games Consoles
    Windows Server 2003 : Planning a Host Name Resolution Strategy - Understanding Name Resolution Requirements
    Google’s Data Liberation Front (Part 2)
    Datacolor SpyderLensCal (Part 1)