none
HLSL Shader Problem: Transparent White rendered as Full White

    Question

  • I am trying to learn HLSL to create WPF Effect shader. I've been using the ShaderEffectsLibrary project, HLSLTester,  and ShaderApp. But I couldn't seem to get the result I wanted. So I made the fx really simple. Basically it makes the image transparent by setting alpha to 0. In the test, I used two images, one as a background (named imgBG), and on top of it is the image (named imgFx) with it's effect set to this custom shader:

    float4 outC;
    outC = tex2d(inputSampler, uv);
    outC.a=0;
    return outC;

    I presumed this would produce a completely transparent imgFx (and imgBG is rendered normally, unaffected). Instead it seems to render #00000000 (0 alpha black) correctly, but any color above complete black is rendered with some alpha, grays with 0 alpha are rendered as partially transparent white. And completely transparent white is rendered as fully opaque white. It's as if the image is rendered with "Screen" blending mode with alpha =1. The rgb value seems to affect the rendered alpha, the higher the rgb value (closer to white) the more opaque they are rendered even when the alpha is 0.

    All other shaders included in ShaderEffectsLibrary project seem work as expected, so the fxc compilation works fine. Is this a bug or am I missing something?

     

     

    Sunday, January 25, 2009 4:19 PM

Answers

  • This isn't a bug, WPF uses pre-multiplied alpha everywhere internally for a number of performance reasons, so that's also the way we interpret the color values in the custom pixel shader.  What this means is that instead of r,g,b,a, the color values are actually drawn as a*r, a*b, a*b, a, so you can see why the blending works out the way it does (all zeroes will be completely transparent black, but (1,1,1,0) will be opaque white).  We thought about doing the conversion between pre-multiplied and non-pre-multiplied colors where we expose the custom shaders, but for the most part the effects we tried out work fine in this space so we didn't want to pay that extra conversion cost.  It's something we'll think about exposing in the future, though, as there are some valid scenarios, like yours, where things would be much easier without the pre-multiplication.
    Monday, January 26, 2009 9:34 PM
  • Yes, that is the behavior in WPF with ShaderEffects.  I'm not sure if it is an artifact of the WPF implementation of ShaderEffects. 

    DirectX/HLSL supports many things that are not available yet in WPF (vertex shaders for one).  DirectX also has blend modes (SourceBlend, AlphaBlend,DestBlend) whch I don't think are available in WPF.

    You can set the opacity property on the Image elemment (if that helps).

     

     

    ** Free WPF shader utiliy **
    ** edit HLSL
    ** auto generates your C#/VB shader classes **
    ** auto generates test pages **

    Shazzam - Open source pixel shader utility


    Walt | http://wpfwonderland.wordpress.com
    • Edited by Walt Ritscher Monday, January 26, 2009 5:24 AM Fix image
    • Marked as answer by Tao Liang Wednesday, January 28, 2009 10:31 AM
    Monday, January 26, 2009 5:23 AM

All replies

  • Yes, that is the behavior in WPF with ShaderEffects.  I'm not sure if it is an artifact of the WPF implementation of ShaderEffects. 

    DirectX/HLSL supports many things that are not available yet in WPF (vertex shaders for one).  DirectX also has blend modes (SourceBlend, AlphaBlend,DestBlend) whch I don't think are available in WPF.

    You can set the opacity property on the Image elemment (if that helps).

     

     

    ** Free WPF shader utiliy **
    ** edit HLSL
    ** auto generates your C#/VB shader classes **
    ** auto generates test pages **

    Shazzam - Open source pixel shader utility


    Walt | http://wpfwonderland.wordpress.com
    • Edited by Walt Ritscher Monday, January 26, 2009 5:24 AM Fix image
    • Marked as answer by Tao Liang Wednesday, January 28, 2009 10:31 AM
    Monday, January 26, 2009 5:23 AM
  • Thanks for the confirmation. What I'm creating is an effect similar to emboss, but instead of making everything opague gray, it only create highlight and shadows on edges of alpha changes. I use this by creating a thin Border element, then applying the effect. The result the border loses it's color replaced by slightly transparent shadow and highlight that makes the border appears carved in. So the element opacity wouldn't help

    I managed to make the effect work, but it was much more complicated and confusing then it should be, since now I have to calculated blacks and whites with different logic.

    I just played with Shazzam, it's  a great tool! I wish It has the option to layer a background Image behind the image with fx, so we can see how the effect affects opacity.


    Monday, January 26, 2009 6:29 AM
  •  

    In Shazzam the background for images is set to a dark blue color.  I was testing your code last night and could see the blue color showing through my test image.

    What I should do is put a black and white checkered pattern (like many of the image editing tools do) for the background.  Sounds like a good idea, I'll put on the feature request list.


    Walt | http://wpfwonderland.wordpress.com
    Monday, January 26, 2009 6:28 PM
  • This isn't a bug, WPF uses pre-multiplied alpha everywhere internally for a number of performance reasons, so that's also the way we interpret the color values in the custom pixel shader.  What this means is that instead of r,g,b,a, the color values are actually drawn as a*r, a*b, a*b, a, so you can see why the blending works out the way it does (all zeroes will be completely transparent black, but (1,1,1,0) will be opaque white).  We thought about doing the conversion between pre-multiplied and non-pre-multiplied colors where we expose the custom shaders, but for the most part the effects we tried out work fine in this space so we didn't want to pay that extra conversion cost.  It's something we'll think about exposing in the future, though, as there are some valid scenarios, like yours, where things would be much easier without the pre-multiplication.
    Monday, January 26, 2009 9:34 PM
  • Now everything makes more sense. Is this mentioned anywhere in the help? Are there samples for similar partially transparent effects ? It's been hard finding information about HLSL, either they are for XNA , which focus mostly with vertex shader, or they are specific to WPF but only deal with opaque effects.

     

    Thanks.
    Wednesday, January 28, 2009 12:32 PM
  • If you want to learn by example we've published a suite of shader effects with source code here:

    http://www.codeplex.com/wpffx

    Can you elaborate a bit on exactly what you're trying to accomplish?  If all you want to do is set the opacity on something then it's much cheaper to use the Opacity property than a ShaderEffect.  The only thing that I can think of off the top of my head is that you might want to do something like a partial color-key, where instead of making a specific color completely transparent you want to make it partially transparent.  In order to work around the pre-multiplication you can adjust the values yourself: divide r,g,b by a to get the unpremultiplied color value, set the new alpha value, and multiply it back in.  Of course this isn't ideal for a number of reasons (loss of precision, the use of many of the precious few instruction slots available in shader model 2.0) but for something simple it should work well enough.

    I couldn't find any published note of this in our documentation so I'll be sure to bring it up so that it gets added on MSDN.  I believe the same assumption applies to D3DImage, where we assume the surface, if it has alpha, is pre-multiplied.

    Wednesday, January 28, 2009 6:45 PM
  • I actually made my carved/etched-in effect by modifying the emboss code from the wpffx samples.
    The problem is basically I'm not too familiar with graphic programming. WPF effect is basically the first cool graphic  programming that is simple enough for me to understand that I want to try it. So it would help if the WPF documentation assumes the programmer are probably less experienced in graphic than typical game programmers that usually deals with shader effects. It would much help for me at least, if the premultification, and the even simple method of dividing rgb the alpha is mentioned in the documentation or shown in the wpffx samples.

    One effect I want to know how to do is inner shadow/inner glow, and other effects that follows the contour of the element it's applied to. It'd be to great if we get to see the code for the built-in hardware accelerated drop shadow.

    Thank you.

    Thursday, January 29, 2009 2:45 AM
  • Here's my actual carved effect code. I have a feeling there's much simpler way with a few lines to achieve this, but I couldn't figure it out.

    //-------------------------------------------------------------------------------------- 
    //  
    // WPF ShaderEffect HLSL Template 
    // 
    //-------------------------------------------------------------------------------------- 
     
    //----------------------------------------------------------------------------------------- 
    // Shader constant register mappings (scalars - float, double, Point, Color, Point3D, etc.) 
    //----------------------------------------------------------------------------------------- 
     
    float amount : register(C0); 
    float width : register(C1); 
     
    //-------------------------------------------------------------------------------------- 
    // Sampler Inputs (Brushes, including ImplicitInput) 
    //-------------------------------------------------------------------------------------- 
     
    sampler2D input : register(S0); 
     
     
    //-------------------------------------------------------------------------------------- 
    // Pixel Shader 
    //-------------------------------------------------------------------------------------- 
     
    float4 main(float2 uv : TEXCOORD) : COLOR 
        
     
        float4 outC=0; 
            
        //sample upper left 
        float4 leftTop = tex2D(input, uv - width) ; 
        //sample bottom right 
        float4 rightBottom =tex2D(input, uv + width) ; 
     
        //Calculate alpha difference between leftTop and RightBottom, to decide whether to make draw the pixel as shadow or highlight 
        float alp=0; 
        alp += leftTop.a * amount; 
        alp -= rightBottom.a * amount; 
      
        //workaround for bug, anything above gray the alpha are multiplied by rgb value 
        //Completely transparent, unchanged 
        if (alp == 0) { 
            //set as 0% Black, so it will be transparent 
            outC = 0; 
        //Lighter 
        } else if (alp > 0) { 
            //set gray rgb (which will act as transparency in addition to color) according to alp, and set alpha to 0 (so it won't add to the transparency) 
            outC.rgb =  alp; 
            //outC.a = 0; 
        } 
        //Darker 
        else { 
            //Set color to Black, adjust alpha according to alp 
            //outC.rgb=0; 
            outC.a = -alp; 
        } 
     
           
        return outC;    
     
     
     
     
    Thursday, January 29, 2009 3:48 AM
  •  
    Tedy Pranolo said:

    I actually made my carved/etched-in effect by modifying the emboss code from the wpffx samples.
    The problem is basically I'm not too familiar with graphic programming. WPF effect is basically the first cool graphic  programming that is simple enough for me to understand that I want to try it. So it would help if the WPF documentation assumes the programmer are probably less experienced in graphic than typical game programmers that usually deals with shader effects. It would much help for me at least, if the premultification, and the even simple method of dividing rgb the alpha is mentioned in the documentation or shown in the wpffx samples.

    One effect I want to know how to do is inner shadow/inner glow, and other effects that follows the contour of the element it's applied to. It'd be to great if we get to see the code for the built-in hardware accelerated drop shadow.

    Thank you.



    The built-in drop shadow and blur use multiple pixel shader passes to achieve their result, which is not something we've directly exposed as of yet in the API.  You can work around this to a small extent by wrapping your content in a Decorator or empty Canvas with another Effect on it, and so on, to nest shaders for multiple passes.  However, you can't directly combine the input from different layers in the tree this way, which is what you would need to do in order to achieve something like a glow, where you want to draw the original content over the top of a blurred and recolored copy of it.  There are ways to hack around it using VisualBrush but it's not easily reusable and will probably not perform as well as we'd like.  We're looking into expanding this feature area to allow for more complex effects, but we don't have anything concrete planned for the immediate future.
    Thursday, January 29, 2009 10:19 PM
  • I realize this is a really old thread, but its one of the few with the answer about WPF using pre-multiplied alpha everywhere, so I thought I'd post my question here in the hopes someone still is getting notifications :)

    I assume texel data without pre-multiplied alpha was never exposed in WPF with .NET 4.5...? I'm using a ShaderEffect to mask color channels so I can allow the user to view just the red, green, blue or alpha (or any combination thereof) in my tool, but my shader keeps receiving texel data that is pre-multiplied by the alpha. Is there any way to do this using WPF and an Image control? I'd like to use a ShaderEffect and let the GPU do the work, but if there's even a way to do it on the CPU in WPF and an Image control, I'd be interested in hearing that method.

    thanks!

    Tuesday, July 2, 2013 5:27 PM