Click here to Skip to main content
Click here to Skip to main content

Anaglyph ShaderEffect in WPF

By , 8 Nov 2009
 
Anaglyph glasses

Introduction

Anaglyph images provide a 3D stereoscopic effect when viewed with red/cyan glasses. This article shows how to use a WPF shader effect to blend a left and right image to produce the anaglyph illusion. This shader can be used for any kind of WPF UIElement.

Using the Code

To use this code in your own project, you should add the class AnaglyphEffect and the pixel shader AnaglyphEffect.ps (compiled HLSL).

Shader Effect

The anaglyph effect combines two image sources, the result is the red channel from the left image source and the green and blue channels from the right image source. The alpha is taken as the max of the two image sources. It is implemented with the following HLSL code:

sampler2D input1 : register(S0); // right image input
sampler2D input2 : register(S1); // left image input
 
float4 main(float2 uv : TEXCOORD) : COLOR
{ 
    float4 Color1; 
    Color1 = tex2D( input1 , uv.xy); 
    
    float4 Color2; 
    Color2 = tex2D( input2 , uv.xy); 

    Color1.r = Color2.r; 
    Color1.g = Color1.g; 
    Color1.b = Color1.b; 
    Color1.a = max(Color1.a,Color2.a);

    return Color1;
}

Remember to save the effect file using Codepage 1252, otherwise fxc will not compile the shader code. In Visual Studio, use "File | Advanced save options..." and select "Western European (Windows) Codepage 1252".

Compiling the Shader Effect

Install Microsoft DirectX SDK, and add the fxc compiler to the path C:/Program Files/Microsoft DirectX SDK (June 2008)/Utilities/bin/x86 or similar.

The shader effect can be compiled with the command:

fxc /T ps_2_0 /E main /Fo AnaglyphEffect.ps AnaglyphEffect.fx

Then, add the compiled pixel shader (.ps) to the project as a Resource.

The shader effect can also be added to your build script with a shader effect build task, see WPF Futures for how to do this.

Shader Effect Class

The AnaglyphEffect class contains dependency properties for LeftInput and RightInput. These Brush inputs are used to define the input sources for the anaglyph blending shader.

I have not been using the RightInput property, since the effect is applied to the right image source element in all these demos.

First Test of the Effect

First, we test the shader with some simple line and text visuals.

If you put on your anaglyph glasses and close your left eye, you should see only "RIGHT" and one of the diagonal lines. Vice versa for the right eye. It is normal to see a weak "ghost" of the "RIGHT" text when using the left eye only.

Sample Image

The source code can be found in TestWindow.xaml:

<Grid>
<Canvas Name="LeftCanvas" Background="White">
    <Polyline Points="20,20 320,320" Stroke="Black" StrokeThickness="16"/>
    <TextBlock Text="Left" Foreground="Black" Canvas.Left="20" Canvas.Top="140" 
    FontSize="40" FontWeight="Bold"/>
</Canvas>
<Canvas Name="RightCanvas" Background="White">
    <Canvas.Effect>
        <cc:AnaglyphEffect x:Name="Effect2">
            <cc:AnaglyphEffect.LeftInput>
                <VisualBrush Visual="{Binding ElementName=LeftCanvas}"/>
            </cc:AnaglyphEffect.LeftInput>
        </cc:AnaglyphEffect>
    </Canvas.Effect>
    <Polyline Points="20,320 320,20" Stroke="Black" StrokeThickness="16"/>
    <TextBlock Text="Right" Foreground="Black" Canvas.Left="220" Canvas.Top="140" 
    FontSize="40" FontWeight="Bold"/>
</Canvas>
</Grid>

Anaglyph Stereo Images

The next test is to blend two images to produce an anaglyph image. This is very easy, we just replace the Polyline/TextBlock elements from the first example with Image elements. I also added mouse capture to be able to move the top level image around. The result looks like this:

Anaglyph image

The images were taken using a tripod and a sliding plate. The distance the camera moved between the two images is called the stereo base. It depends on the distance to the nearest object and the focal length. See the section below about calculating the stereo base. For moving subjects, it is necessary to mount two cameras to a plate and synchronize the shutters exactly.

The XAML source follows:

<Grid>
<Canvas Name="LeftCanvas" Background="White" Width="1000" Height="500">
    <Image Source="images/left.jpg" Width="800" 
              Height="450" Canvas.Left="20" Canvas.Top="20" />
</Canvas>
<Canvas Background="White" Width="1000" Height="500">
    <Image Name="RightImage" Width="800" Height="450" Canvas.Left="20" Canvas.Top="20" 
    Source="images/right.jpg" 
    MouseDown="Image_MouseDown" MouseMove="Image_MouseMove" MouseUp="Image_MouseUp"/>
    <Canvas.Effect>
        <me:AnaglyphEffect x:Name="Effect1">
            <me:AnaglyphEffect.LeftInput>
                <VisualBrush Visual="{Binding ElementName=LeftCanvas}"/>
            </me:AnaglyphEffect.LeftInput>
        </me:AnaglyphEffect>
    </Canvas.Effect>
</Canvas>
</Grid>

Calculating the Stereo Base

The stereo base can be calculated with the Bercovitz formula:

    B = P * (L*N/(L-N)) * (1/F - (L+N) / (2*L*N))

where:

    B = stereo base (distance between the camera optical axes)
    P = parallax aimed for, in mm on the film 
    L = largest distance from the camera lens
    N = nearest distance from the camera lens
    F = focal length of the lens

If you are using the 35mm format, you should aim for a parallax about 1.2mm, this is a ratio of ~ 1/30.
With a nearest distance of 2m, largest distance of 10m and a 50mm lens, the stereo base should be 57mm.

Anaglyph 3D Rendering

We will now use the effect on Viewport3D elements:

Anaglyph Viewport3D

This window contains two Viewport3D elements, one for the left camera and one for the right.

I added a texture to the cube, this improves the perception of the depth.

The left view has a Camera positioned at [-0.15 5 4] pointing towards the origin:

<Grid Name="LeftView" Background="White">
    <Viewport3D >
        <ModelVisual3D>
            ...
        </ModelVisual3D>
        <Viewport3D.Camera>
            <PerspectiveCamera x:Name="LeftCamera" 
                       Position="-0.15 5 4"
                       LookDirection="0 -5 -4"
                       UpDirection="0 0 1"
                       FieldOfView="75"
                       NearPlaneDistance="0.15"/>
        </Viewport3D.Camera>
    </Viewport3D>
</Grid>

And, the right view has a Camera at [0.15 5 4]. The Viewport3D is wrapped in a Grid element, and we add the anaglyph effect to the Grid.Effect property. Also note that I am setting the background colour to white for this to work:

<Grid Background="White">
    <Grid.Effect>
        <me:AnaglyphEffect x:Name="Effect1">
            <me:AnaglyphEffect.LeftInput>
                <VisualBrush Visual="{Binding ElementName=LeftView}"/>
            </me:AnaglyphEffect.LeftInput>
        </me:AnaglyphEffect>
    </Grid.Effect>
    <Viewport3D Name="RightView">
        <ModelVisual3D>
            ...
        </ModelVisual3D>
        <Viewport3D.Camera>
            <PerspectiveCamera x:Name="RightCamera" 
                       Position="0.15 5 4"
                       LookDirection="0 -5 -4"
                       UpDirection="0 0 1"
                       FieldOfView="75"
                       NearPlaneDistance="0.15"/>
        </Viewport3D.Camera>
    </Viewport3D>
</Grid>

Anaglyph 3D Rendering

The solution also contains a project TransparentCube3D, that renders the cube in anaglyph mode on a transparent window.

Phantogram

Phantograms give an optical 3D illusion from a 2D image. When the viewer is placed at the correct point, it looks like the image pops out of the surface. These images should be viewed from a 45 degree angle for the best effect.

Phantogram

This view can be created with the anaglyph shader effect and the following XAML code:

<Grid>
    <Image Name="LeftImage" Source="phantogram/iitala_left.jpg" />
    <Image Name="RightImage" Source="phantogram/iitala_right.jpg">
        <Image.Effect>
            <cc:AnaglyphEffect x:Name="Effect2">
                <cc:AnaglyphEffect.LeftInput>
                    <VisualBrush Visual="{Binding ElementName=LeftImage}"/>
                </cc:AnaglyphEffect.LeftInput>
            </cc:AnaglyphEffect>
        </Image.Effect>
    </Image>
</Grid>

(The vase was designed by Alvar Aalto.)

How to Make a Phantogram

  • Place the item you want on a piece of paper, mark the corners of the paper.
  • Set your camera on a tripod pointing 45 degrees down to the paper.
  • Shoot a left and right picture a few cms apart (the "stereobase") (use a sliding plate if you have one).
  • Crop and correct the perspective of the edges of the paper (in Photoshop, use the Crop tool with the "Perspective" option checked).
  • Resize with unconstrained proportions to the original size of the paper.
  • If displaying the phantogram in a different scale, the "stereobase" should be adjusted accordingly.

Sample Image

Anaglyph Webcam

To show video from a webcam, I use the excellent WpfCap webcam control for WPF. Using two CapPlayer controls and simply adding an anaglyph effect on the last one gives us the blended anaglyph video:

<webcam:CapPlayer Grid.Row="2" Grid.ColumnSpan="2" 
	x:Name="webcamPlayer1" Height="480" 
    Device="{Binding RelativeSource=	{RelativeSource AncestorType=
	{x:Type local:MainWindow}}, Path=SelectedWebcam1}">
</webcam:CapPlayer>
<webcam:CapPlayer Grid.Row="2" Grid.ColumnSpan="2" x:Name="webcamPlayer2" Height="480"
    Device="{Binding RelativeSource={RelativeSource AncestorType=
	{x:Type local:MainWindow}}, Path=SelectedWebcam2}">
    <webcam:CapPlayer.Effect>
        <me:AnaglyphEffect x:Name="Effect1">
            <me:AnaglyphEffect.LeftInput>
                <VisualBrush Visual="{Binding ElementName=webcamPlayer1}"/>
            </me:AnaglyphEffect.LeftInput>
        </me:AnaglyphEffect>
    </webcam:CapPlayer.Effect>
    <webcam:CapPlayer.LayoutTransform>
        <ScaleTransform ScaleX="1" ScaleY="-1"/>
    </webcam:CapPlayer.LayoutTransform>
</webcam:CapPlayer>

For some reason, the webcam control flips the video vertically. I added a ScaleTransform to the LayoutTransform that fixes this, but I hope to see a better solution.

The blended webcam video looks like this:

I used two inexpensive webcams on top of the screen, the alignment of the cameras could be improved.

References / Inspiration

History

  • Jan 18, 2009 - First post
  • March 19, 2009 - Added anaglyph webcam code
  • November 8, 2009 - Added alpha to shader effect, texture to 3D cube, section about the stereo base, transparent window demo

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

objo
Norway Norway
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionHow to do for other colors?memberbensam566 Apr '12 - 3:08 
Hi, Thanks for this project. It works pretty fine. You made this for Anaglyph Red - Cyan combination. How can I do with Cyan - Red, Yellow - Blue, Blue - Yellow, Green - Magenta and Magenta - Green?
Thanks!
 
Regards,
Benjamin
QuestionGreatmemberKanasz Robert8 Nov '11 - 0:05 
your article is really great. you've got my 5. Smile | :)
GeneralSmall querymemberdeepak080220 Jan '10 - 0:11 
Initially I would like to thank you for this wonderful article .. This is really cool ...
 
But I have a query ..
 
As per my understanding, the anaglyph image that is displayed here is not actually an image but illusion created by overlapping two images. So if I want to save the anaglyph image, how can I do that ...?
 
Thanks in advance...
Generalusing in own projectmemberTóth Ádám6 Jan '10 - 2:38 
Hi,
 
the post was great, I even tried the binaries & liked them!
I have a problem using the effect in my own project.
As I read, I have to use the ".cs" & the ".ps" file.
I added the class to my project & modified my xaml.
But where do I have to put the ".ps" file? I tried to add it as a Resource (Project/Properties/Resources.resx), but I guess that's not the thing I should have done.
I get an Exception at InitializeComponent, where the base InnerException says, that anaglypheffect.ps can not be found.
Anything to do with the dll file?
 
Thanks:
Ádám
GeneralRe: using in own projectmemberobjo9 Jan '10 - 0:30 
hi Ádám,
the compiled shader file (.ps) must be included in your project with build action "Resource". If you rename/relocate the resource you may have to modify the UriSource of the pixel shader - see the static constructor in the AnaglyphEffect class! If you reference the AnaglyphEffect.dll assembly (as I did in the demos) you don't have to worry about this.
GeneralTruly awesomememberrohits197927 Jul '09 - 5:18 
You got my 7 stars out of 5 Wink | ;) , well written and well done.Thumbs Up | :thumbsup:
GeneralRe: Truly awesomememberobjo10 Nov '09 - 11:05 
hi Rohit, thanks for the feedback! you got an updated article with Bercovitz formula, texture on the cubes and transparent window for those two extra stars Smile | :)
GeneralAnaglyph webcammemberobjo19 Mar '09 - 12:54 
I just updated the article with the anaglyph effect applied to two webcams. The result is quite cool Smile | :) Takes some time to adjust the cameras right, I'm still not quite finished there...
GeneralExcellent workmvpMika Wendelius31 Jan '09 - 5:10 
Tested it and it was really cool!
 
The need to optimize rises from a bad design.My articles[^]

GeneralRe: Excellent workmemberobjo19 Mar '09 - 12:52 
Thank you! It's inspiring to get such positive feedback Smile | :)
GeneralHoly crap.mvpPete O'Hanlon21 Jan '09 - 9:17 
This is some amazing stuff - nice one, lots of nice one there. My 5 to add to the other 5s.
 
"WPF has many lovers. It's a veritable porn star!" - Josh Smith
 

My blog | My articles | MoXAML PowerToys



GeneralRe: Holy crap.memberobjo22 Jan '09 - 9:05 
Thank you!! I'm glad you liked it! I'll post an update on the 3d webcam video later, if it works out.
GeneralVery cool indeedmvpSacha Barber21 Jan '09 - 4:32 
Just as cool as my bloody valentine.
 
Sacha Barber
  • Microsoft Visual C# MVP 2008
  • Codeproject MVP 2008
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralRe: Very cool indeedmemberobjo22 Jan '09 - 9:04 
Thanks for the comment! I had to pick up a copy of the Polar Express movie to get these anaglyph glasses, I'll check out the bloody valentine next time Smile | :)
GeneralRe: Very cool indeedmvpSacha Barber22 Jan '09 - 9:58 
Cool. They are making 3d tv with wiggly screens to create 3D effects I read somewhere today. Cool
 
Sacha Barber
  • Microsoft Visual C# MVP 2008
  • Codeproject MVP 2008
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

QuestionWhat can I say?mvpJosh Smith21 Jan '09 - 4:01 
This is Awesome! Nice job. Got my 5. Cool | :cool:
 
:josh:
Try Crack![^]
Sleep is overrated.

AnswerRe: What can I say?memberobjo22 Jan '09 - 8:56 
Thank you! I think it's very cool how easy it is to do things like this in WPF! An update on 3D webcam video is coming later Smile | :)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 8 Nov 2009
Article Copyright 2009 by objo
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid