Announcement

Collapse
No announcement yet.

DrawableTexture with alpha channel image

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • DrawableTexture with alpha channel image

    What's the correct way to render DrawableTexture with alpha channel image. The DrawableTexture's color is different from source image when change the clear value (Texture.Clear(FloatColor($00FFFFFFFF)).I don't want to clear with $FFFFFFFF or other non-transparent value,because it must blend with background.

    Click image for larger version  Name:	XjYRsI7.jpg Views:	0 Size:	110.3 KB ID:	192



    Code:
    FillChar(LParameters, SizeOf(TTextureParameters), 0);
    LParameters.Width := 567;
    LParameters.Height := 600;
    LParameters.Attributes := TextureDrawable;
    LParameters.Format := TPixelFormat.RGBA8;
    DrawableTexture := TextureInit(FDevice, LParameters);
    SourceTexture := TextureInit(FDevice, 'c:/Test.png');
    
    procedure TMainForm.RepaintWindow;
    var
      LFontSettings: TFontSettings;
      LFlipped: Boolean;
      LTexCoords: TQuad;
    begin
    
      if LFlipped then
        LTexCoords := QuadUnity.Flip
      else
        LTexCoords := QuadUnity;
    
      if DrawableTexture.Initialized then
      begin
      //DrawableTexture.Clear(FloatColor($00FFFFFF));
        //DrawableTexture.Clear(FloatColor($00AAAAAA));
        //DrawableTexture.Clear(FloatColor($00FFFFFF));
         DrawableTexture.Clear(FloatColor($0));
        if DrawableTexture.BeginScene then
        try
          if FCanvas.BeginScene then
          try
            FCanvas.Quad(SourceTexture, Quad(0, 0, 567, 600), LTexCoords, $FFFFFFFF);
            LFontSettings := TFontSettings.Create('Segoe UI', 28.0 * FDisplayScale, TFontWeight.Thin);
            LFontSettings.Effect.BorderType := TFontBorder.None;
            FTextRenderer.FontSettings := LFontSettings;
            FTextRenderer.Draw(Point2f(156.0, 510.0), 'Drawable Texture', ColorPair($FFFFFFFF));
          finally
            FCanvas.EndScene;
          end;
        finally
          DrawableTexture.EndScene;
        end;
      end;
    
      if FDevice.Initialized and FDevice.BeginScene then
      try
        FDevice.Clear([TClearLayer.Color], FloatColor($FFBBBBBB));
        if FCanvas.BeginScene then
        try
          FCanvas.Quad(SourceTexture, Quad(0, 100, 567, 600), LTexCoords, $FFFFFFFF);
    
          LFontSettings := TFontSettings.Create('Segoe UI', 28.0 * FDisplayScale, TFontWeight.Thin);
          LFontSettings.Effect.BorderType := TFontBorder.None;
          FTextRenderer.FontSettings := LFontSettings;
          FTextRenderer.Draw(Point2f(156.0, 610.0), 'Source Texture', ColorPair($FFFFFFFF));
    
          FCanvas.Quad(DrawableTexture, Quad(600, 100, 567, 600), LTexCoords, $FFFFFFFF);
        finally
          FCanvas.EndScene;
        end;
      finally
        FDevice.EndScene;
      end;
    
      FTimer.Execute(True, False);
    end;

  • #2
    It appears that your original texture image is created with premultiplied alpha, where each pixel's red, green and blue values are already multiplied by the value of alpha-channel.

    You should include TexturePremultipliedAlpha flag when creating that texture:
    Code:
    SourceTexture := TextureInit(FDevice, 'c:/Test.png', TPixelFormat.RGBA8, TexturePremultipliedAlpha);
    P.S. Out of curiosity, how did you create this lightning-looking image?

    Comment


    • #3
      Still the same problem !

      Originally posted by lifepower View Post
      P.S. Out of curiosity, how did you create this lightning-looking image?
      Not made by me,it take from a website.

      Comment


      • #4
        Can you please attach a small compilable example that reproduces the issue? Or at least a portion of original texture that I can try?

        Comment


        • #5
          Here
          drawableTexture.zip

          Comment


          • #6
            The TextRenderer have the same problem when change the clear value( DrawableTexture.Clear(FloatColor($XXXXXXXX)); )

            Click image for larger version

Name:	18PIuqO.jpg
Views:	31
Size:	11.8 KB
ID:	199

            Comment


            • #7
              I am sorry, I didn't realize you were having problem with drawable texture and not the texture loaded from disk. You need to add "TexturePremultipliedAlpha" to drawable texture parameters in this case, so change this code:
              Code:
              FillChar(LParameters, SizeOf(TTextureParameters), 0);
              LParameters.Width := 567;
              LParameters.Height := 600;
              LParameters.Attributes := TextureDrawable;
              LParameters.Format := TPixelFormat.RGBA8;
              LParameters.Multisamples := 8;
              
              DrawableTexture := TextureInit(FDevice, LParameters);
              to this:

              Code:
              FillChar(LParameters, SizeOf(TTextureParameters), 0);
              LParameters.Width := 567;
              LParameters.Height := 600;
              LParameters.Attributes := TextureDrawable or TexturePremultipliedAlpha;
              LParameters.Format := TPixelFormat.RGBA8;
              LParameters.Multisamples := 0;
              
              DrawableTexture := TextureInit(FDevice, LParameters);
              In above code, I also have set "Multisamples" to 0, because you must not draw multisampled texture on canvas directly, you must resolve it (e.g. by using TTexture.Copy) to a non-multisample texture first.

              Comment


              • #8
                Originally posted by DraculaLin View Post
                Not made by me,it take from a website.
                I'm asking because it looks very similar to images generated by NoisePlus tool which I was making back in 2005 (wow, 15 years ago, I'm getting old... ) and only shared it with a friend. Maybe after 15 years I need to finish it some day!

                Click image for larger version  Name:	noiseplus.png Views:	0 Size:	76.4 KB ID:	202

                Comment


                • #9
                  Thanks,this work.That just a simple property setting but to annoy and confuse developers.

                  Comment


                  • #10
                    Hi again,the TextRenderer become blur when use Canvas.FillRect ?
                    Code:
                    LParameters.Attributes := TextureDrawable or TexturePremultipliedAlpha;
                    LParameters.Format := TPixelFormat.RGBA8;
                    LParameters.Multisamples := 0;
                    DestTexture := TextureInit(FDevice, LParameters);
                    DrawableTexture := TextureInit(FDevice, LParameters);
                    ...........
                    ...........
                     if DrawableTexture.Initialized then
                      begin
                        DrawableTexture.Clear;
                        if DrawableTexture.BeginScene then
                        try
                          if FCanvas.BeginScene then
                          try
                            FCanvas.FillRect(FloatRect(50, 200, 400, 500), ColorRect($5300FFAA));
                            LFontSettings := TFontSettings.Create('Arial', 13, TFontWeight.Thin);
                            LFontSettings.Effect.BorderType := TFontBorder.None;
                            FTextRenderer.FontSettings := LFontSettings;
                            FTextRenderer.Draw(Point2f(156.0, 510.0),' WWww Test  WWwDrawable Texture', ColorPair($FF00FFFF));
                          finally
                            FCanvas.EndScene;
                          end;
                        finally
                          DrawableTexture.EndScene;
                        end;
                      end;
                      DestTexture.Copy(@DrawableTexture, 0, ZeroPoint2i, 0, ZeroIntRect);
                    ........
                    ........
                    Last edited by DraculaLin; 04-12-2020, 02:29 PM.

                    Comment


                    • #11
                      First of all, before drawing text, make sure to issue these calls:
                      Code:
                      FCanvas.ContextState := TCanvasContextState.FlatText;
                      FCanvas.SetSamplerState(TCanvasSamplerState.Create (TTextureFilter.Nearest, TTextureFilter.Nearest));
                      For rendering images and shapes, you should use TCanvasContextState.FlatScene instead. However, in your case these options are not related to your problem. The problem is that you are essentially trying to alpha-compose an image. I am not 100% sure, but I believe this should work:
                      Code:
                      if FCanvas.BeginScene then
                      try
                      FCanvas.ContextState := TCanvasContextState.FlatScene;
                      
                      FCanvas.FillRect(FloatRect(50, 200, 400, 500), ColorRect($5300FFAA));
                      FCanvas.Flush;
                      
                      FCanvas.ContextState := TCanvasContextState.FlatText;
                      FCanvas.SetSamplerState(TCanvasSamplerState.Create (TTextureFilter.Nearest, TTextureFilter.Nearest));
                      
                      FillChar(LModifiers, SizeOf(TTextRenderModifiers), 0);
                      LModifiers.Effect := TBlendingEffect.Undefined;
                      
                      LFontSettings := TFontSettings.Create('Arial', 13, TFontWeight.Thin);
                      LFontSettings.Effect.BorderType := TFontBorder.None;
                      FTextRenderer.FontSettings := LFontSettings;
                      FTextRenderer.Draw(Point2f(156.0, 510.0),' WWww Test WWwDrawable Texture', ColorPair($FF00FFFF),
                      1.0, @LModifiers);
                      
                      // Override alpha-blending state.
                      LRenderState := FDevice.RenderingState;
                      LRenderState.BlendColor.Source := TBlendFactor.One;
                      LRenderState.BlendColor.Dest := TBlendFactor.InvSourceAlpha;
                      LRenderState.BlendColor.Op := TBlendOp.Add;
                      LRenderState.BlendAlpha.Source := TBlendFactor.One;
                      LRenderState.BlendAlpha.Dest := TBlendFactor.InvSourceAlpha;
                      LRenderState.BlendAlpha.Op := TBlendOp.Add;
                      FDevice.RenderingState := LRenderState;
                      
                      FCanvas.Flush;
                      finally
                      FCanvas.EndScene;
                      end;
                      Please try and see if it gives the desired effect. If really needed, this specific blending state can be introduced to canvas in Afterwarp, something like TBlendingEffect.AlphaCompose.

                      Comment


                      • #12
                        Work perfect !
                        But i get the same effect when i commented out these code.

                        Code:
                        // FCanvas.ContextState := TCanvasContextState.FlatScene;
                        FCanvas.FillRect(FloatRect(50, 200, 400, 500), ColorRect($5300FFAA));
                        // FCanvas.Flush;
                        // FCanvas.ContextState := TCanvasContextState.FlatText;
                        // FCanvas.SetSamplerState(TCanvasSamplerState.Create (TTextureFilter.Nearest, TTextureFilter.Nearest));
                        // FillChar(LModifiers, SizeOf(TTextRenderModifiers), 0);
                        // LModifiers.Effect := TBlendingEffect.Undefined;
                        LFontSettings := TFontSettings.Create('Arial', 13, TFontWeight.Thin);
                        LFontSettings.Effect.BorderType := TFontBorder.None;
                        FTextRenderer.FontSettings := LFontSettings;
                        FTextRenderer.Draw(Point2f(156.0, 510.0), 'Lucas WWwDrawable Texture', ColorPair($FF00FFFF));
                        LRenderState := FDevice.RenderingState;
                        LRenderState.BlendColor.Source := TBlendFactor.One;
                        LRenderState.BlendColor.Dest := TBlendFactor.InvSourceAlpha;
                        LRenderState.BlendColor.Op := TBlendOp.Add;
                        LRenderState.BlendAlpha.Source := TBlendFactor.One;
                        LRenderState.BlendAlpha.Dest := TBlendFactor.InvSourceAlpha;
                        LRenderState.BlendAlpha.Op := TBlendOp.Add;
                        FDevice.RenderingState := LRenderState;
                        // FCanvas.Flush;

                        Comment


                        • #13
                          The previous problem appear when save to file. Test2.png lost PremultipliedAlpha, how to fix?
                          Code:
                          SourceTexture := TextureInit(FDevice, 'Test.png',TPixelFormat.RGBA8, TexturePremultipliedAlpha);
                          SourceTexture.SaveToFile('c:/Test2.png',nil, 0, ZeroIntRect);

                          Comment


                          • #14
                            As far as I know, PNG does not store information on whether the colors are premultiplied by their alpha-channel or not, so it's up to each application to figure that out. However, if the issue appears when you load PNG back, then it could be a bug.

                            In the incoming Afterwarp v2, by the way, you don't need to override blending state as in my previous post, now TBlendingEffect.Normal properly composes alpha-channel.

                            Comment

                            Working...
                            X