是否有针对UWP合成API的非Win2D文本解决方案

是否有针对UWP合成API的非Win2D文本解决方案,uwp,windows-runtime,win2d,Uwp,Windows Runtime,Win2d,为了避免XY问题,首先问Y:有没有办法在SpriteVisual上创建不需要Win2D的文本 现在,我要解决的问题是,我需要SpriteVisual(而不是TextBlock)上的文本来应用透视旋转3D表达式动画。SpriteVisual上的文本可以使用Win2D完成。这里有一个例子: 要在其中为文本着色,需要Win2D笔刷。但是我想在表达式动画中设置颜色的动画,所以我需要文本颜色来自合成笔刷。现在我可以创建一个CompositionMaskBrush,其中文本笔刷作为掩码,Compositio

为了避免XY问题,首先问Y:有没有办法在SpriteVisual上创建不需要Win2D的文本

现在,我要解决的问题是,我需要SpriteVisual(而不是TextBlock)上的文本来应用透视旋转3D表达式动画。SpriteVisual上的文本可以使用Win2D完成。这里有一个例子:

要在其中为文本着色,需要Win2D笔刷。但是我想在表达式动画中设置颜色的动画,所以我需要文本颜色来自合成笔刷。现在我可以创建一个CompositionMaskBrush,其中文本笔刷作为掩码,CompositionBrush作为源。但使用合成MaskBrush,我无法添加额外的遮罩或任何其他合成效果,这对我来说是个问题


在我不熟悉的内部构建中,是否有一种替代方法或可能是对合成API的增强?

Y-回答:不,您只能使用Win2d
CanvasDrawingSession
CompositionDrawingSurface
上绘制文本。但是您可以使用
ElementCompositionPreview.GetElementVisual(yourTextBlock)
从XAML
TextBlock
获取
Visual
,并使用Composition API表达式+XAML彩色故事板对其进行动画制作

X-answer:您可以从文本
CompositionDrawingSurface
创建alpha遮罩,并将其应用于
CompositionColorBrush

    private void CreateColoredText(string text)
    {
        var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
        var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, CanvasDevice.GetSharedDevice());

        var spriteTextVisual = compositor.CreateSpriteVisual();
        spriteTextVisual.Size = new Vector2(512, 512);

        var maskDrawingSurface = graphicsDevice.CreateDrawingSurface(new Size(512, 512), DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);

        using (var ds = CanvasComposition.CreateDrawingSession(maskDrawingSurface))
        {
            ds.Clear(Colors.Transparent);
            ds.DrawText(text, new Rect(0, 0, 512, 512), Colors.Lime, new CanvasTextFormat
            {
                FontSize = 32,
                FontWeight = FontWeights.Bold,
                VerticalAlignment = CanvasVerticalAlignment.Center,
                HorizontalAlignment = CanvasHorizontalAlignment.Center,
                LineSpacing = 32
            });
        }

        var maskSurfaceBrush = compositor.CreateSurfaceBrush(maskDrawingSurface);
        var surfaceTextBrush = compositor.CreateColorBrush(Colors.DeepPink);
        var maskBrush = compositor.CreateMaskBrush();
        maskBrush.Mask = maskSurfaceBrush;
        maskBrush.Source = surfaceTextBrush;

        var colorAnimation = compositor.CreateColorKeyFrameAnimation();
        colorAnimation.InsertKeyFrame(0.5f, Colors.DeepSkyBlue);
        colorAnimation.InsertKeyFrame(1, Colors.DeepPink);
        colorAnimation.Duration = TimeSpan.FromMilliseconds(1500);
        colorAnimation.IterationBehavior = AnimationIterationBehavior.Forever;

        surfaceTextBrush.StartAnimation("Color", colorAnimation);

        spriteTextVisual.Brush = maskBrush;

        ElementCompositionPreview.SetElementChildVisual(Grid, spriteTextVisual);
    }

现在,您可以为自己的目的设置颜色和透视动画。

我需要对其进行处理,但一些可能的问题已经超出了我的想象。TextBlock是否需要添加到可视化树中才能使其可视化工作?VisualElement可以添加到ContainerVersion中吗?很显然,它不能。PlaneProjection动画通过将深度变换应用于ContainerVisual,然后设置子对象(嵌套容器或精灵)旋转的动画来工作。表达式也在容器上,因为有同级的视觉效果,比如文本的背景。新的RedirectVisual可能会有所帮助,但无法在其上找到任何文档。此外,关于合成MaskBrush,我已经提到了这一点,这正是我现在正在做的,但一旦你这样做,你就不能将其嵌套在另一个遮罩中或向其添加其他合成效果(例如饱和或色调旋转)好吧,我错了,编译器允许你向ContainerVisual添加一个元素,但是我从一个文本块中添加了一个元素,其中包含文本,它没有显示任何内容。我一直在尝试这个。TextBlock解决方案不起作用。重定向视觉可以工作,但文本块本身必须添加到XAML视觉树中,并且无论发生什么,它都必须绘制像素。折叠UIElement或设置0不透明度(或甚至0.01不透明度)将使重定向的视觉对象为空。因此,即使您可以将一个元素的视觉效果放在ContainerVisual中,出于所有实际目的,它也不会完成任何事情,而重定向视觉效果也不会工作,除非原始效果也被绘制在屏幕上,这将是一个非常不寻常的用例。
    private void CreateColoredText(string text)
    {
        var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
        var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, CanvasDevice.GetSharedDevice());

        var spriteTextVisual = compositor.CreateSpriteVisual();
        spriteTextVisual.Size = new Vector2(512, 512);

        var maskDrawingSurface = graphicsDevice.CreateDrawingSurface(new Size(512, 512), DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);

        using (var ds = CanvasComposition.CreateDrawingSession(maskDrawingSurface))
        {
            ds.Clear(Colors.Transparent);
            ds.DrawText(text, new Rect(0, 0, 512, 512), Colors.Lime, new CanvasTextFormat
            {
                FontSize = 32,
                FontWeight = FontWeights.Bold,
                VerticalAlignment = CanvasVerticalAlignment.Center,
                HorizontalAlignment = CanvasHorizontalAlignment.Center,
                LineSpacing = 32
            });
        }

        var maskSurfaceBrush = compositor.CreateSurfaceBrush(maskDrawingSurface);
        var surfaceTextBrush = compositor.CreateColorBrush(Colors.DeepPink);
        var maskBrush = compositor.CreateMaskBrush();
        maskBrush.Mask = maskSurfaceBrush;
        maskBrush.Source = surfaceTextBrush;

        var colorAnimation = compositor.CreateColorKeyFrameAnimation();
        colorAnimation.InsertKeyFrame(0.5f, Colors.DeepSkyBlue);
        colorAnimation.InsertKeyFrame(1, Colors.DeepPink);
        colorAnimation.Duration = TimeSpan.FromMilliseconds(1500);
        colorAnimation.IterationBehavior = AnimationIterationBehavior.Forever;

        surfaceTextBrush.StartAnimation("Color", colorAnimation);

        spriteTextVisual.Brush = maskBrush;

        ElementCompositionPreview.SetElementChildVisual(Grid, spriteTextVisual);
    }