使 UIElement 仅在 SpotLight 下可见
Make UIElement visible only under SpotLight
我有一个矩形:
<Border x:Name="Elem1" BorderThickness="2" Height="100" Width="200" BorderBrush="Red" />
还有一个 Windows.UI.Composition.SpotLight 与指针一起移动:
const float LightDistance = 20;
_compositor = Window.Current.Compositor;
_pointLight = _compositor.CreatePointLight();
_pointLight.Color = Colors.White;
_pointLight.Targets.Add(ElementCompositionPreview.GetElementVisual(Elem1));
PointerMoved += (o, e) => {
var point = e.GetCurrentPoint(this).Position;
_pointLight.Offset = new Vector3((float)point.X, (float)point.Y, LightDistance);
};
当矩形上没有光时,它保持黑色:
我希望矩形的其余部分是透明的,所以只有亮起的部分可见
我尝试添加透明的 AmblientLight,但 aplha 通道被忽略了。
我想 SceneLightingEffect
可以实现,但是怎么做呢? :)
特别适合你:D
public MainPage()
{
InitializeComponent();
Loaded += MainPage_Loaded;
}
private CompositionSurfaceBrush _maskSurfaceBrush;
private readonly float _size = 512;
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
PointerMoved += MainPage_PointerMoved;
var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
var canvasDevice = CanvasDevice.GetSharedDevice();
var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, canvasDevice);
var canvasBitmap = await CanvasBitmap.LoadAsync(canvasDevice, new Uri("ms-appx:///Assets/44578.jpg"));
var sourceDrawingSurface = graphicsDevice.CreateDrawingSurface(new Size(_size, _size), DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
using (var ds = CanvasComposition.CreateDrawingSession(sourceDrawingSurface))
{
ds.Clear(Colors.Transparent);
ds.DrawImage(canvasBitmap);
}
var sourceSurfaceBrush = compositor.CreateSurfaceBrush(sourceDrawingSurface);
var maskRenderTarget = new CanvasRenderTarget(canvasDevice, _size, _size, 96);
using (var ds = maskRenderTarget.CreateDrawingSession())
{
ds.Clear(Colors.Transparent);
ds.FillCircle(_size / 2, _size / 2, _size / 8, Colors.Black);
}
var blur = new GaussianBlurEffect
{
BlurAmount = 16,
Source = maskRenderTarget
};
var blurredMaskDrawingSurface = graphicsDevice.CreateDrawingSurface(new Size(_size, _size), DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
using (var ds = CanvasComposition.CreateDrawingSession(blurredMaskDrawingSurface))
{
ds.Clear(Colors.Transparent);
ds.DrawImage(blur);
}
_maskSurfaceBrush = compositor.CreateSurfaceBrush(blurredMaskDrawingSurface);
var composite = new CompositeEffect
{
Sources = { new CompositionEffectSourceParameter("source"), new CompositionEffectSourceParameter("mask") },
Mode = CanvasComposite.DestinationAtop
};
var effectFactory = compositor.CreateEffectFactory(composite);
var fxBrush = effectFactory.CreateBrush();
fxBrush.SetSourceParameter("source", sourceSurfaceBrush);
fxBrush.SetSourceParameter("mask", _maskSurfaceBrush);
var sprite = compositor.CreateSpriteVisual();
sprite.Size = new Vector2(_size, _size);
sprite.Brush = fxBrush;
ElementCompositionPreview.SetElementChildVisual(this, sprite);
}
private void MainPage_PointerMoved(object sender, PointerRoutedEventArgs e)
{
var position = e.GetCurrentPoint(this).Position.ToVector2();
_maskSurfaceBrush.Offset = position - new Vector2(_size / 2, _size / 2);
}
比以往任何时候都更好用!
我有一个矩形:
<Border x:Name="Elem1" BorderThickness="2" Height="100" Width="200" BorderBrush="Red" />
还有一个 Windows.UI.Composition.SpotLight 与指针一起移动:
const float LightDistance = 20;
_compositor = Window.Current.Compositor;
_pointLight = _compositor.CreatePointLight();
_pointLight.Color = Colors.White;
_pointLight.Targets.Add(ElementCompositionPreview.GetElementVisual(Elem1));
PointerMoved += (o, e) => {
var point = e.GetCurrentPoint(this).Position;
_pointLight.Offset = new Vector3((float)point.X, (float)point.Y, LightDistance);
};
当矩形上没有光时,它保持黑色:
我希望矩形的其余部分是透明的,所以只有亮起的部分可见
我尝试添加透明的 AmblientLight,但 aplha 通道被忽略了。
我想 SceneLightingEffect
可以实现,但是怎么做呢? :)
特别适合你:D
public MainPage()
{
InitializeComponent();
Loaded += MainPage_Loaded;
}
private CompositionSurfaceBrush _maskSurfaceBrush;
private readonly float _size = 512;
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
PointerMoved += MainPage_PointerMoved;
var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
var canvasDevice = CanvasDevice.GetSharedDevice();
var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, canvasDevice);
var canvasBitmap = await CanvasBitmap.LoadAsync(canvasDevice, new Uri("ms-appx:///Assets/44578.jpg"));
var sourceDrawingSurface = graphicsDevice.CreateDrawingSurface(new Size(_size, _size), DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
using (var ds = CanvasComposition.CreateDrawingSession(sourceDrawingSurface))
{
ds.Clear(Colors.Transparent);
ds.DrawImage(canvasBitmap);
}
var sourceSurfaceBrush = compositor.CreateSurfaceBrush(sourceDrawingSurface);
var maskRenderTarget = new CanvasRenderTarget(canvasDevice, _size, _size, 96);
using (var ds = maskRenderTarget.CreateDrawingSession())
{
ds.Clear(Colors.Transparent);
ds.FillCircle(_size / 2, _size / 2, _size / 8, Colors.Black);
}
var blur = new GaussianBlurEffect
{
BlurAmount = 16,
Source = maskRenderTarget
};
var blurredMaskDrawingSurface = graphicsDevice.CreateDrawingSurface(new Size(_size, _size), DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
using (var ds = CanvasComposition.CreateDrawingSession(blurredMaskDrawingSurface))
{
ds.Clear(Colors.Transparent);
ds.DrawImage(blur);
}
_maskSurfaceBrush = compositor.CreateSurfaceBrush(blurredMaskDrawingSurface);
var composite = new CompositeEffect
{
Sources = { new CompositionEffectSourceParameter("source"), new CompositionEffectSourceParameter("mask") },
Mode = CanvasComposite.DestinationAtop
};
var effectFactory = compositor.CreateEffectFactory(composite);
var fxBrush = effectFactory.CreateBrush();
fxBrush.SetSourceParameter("source", sourceSurfaceBrush);
fxBrush.SetSourceParameter("mask", _maskSurfaceBrush);
var sprite = compositor.CreateSpriteVisual();
sprite.Size = new Vector2(_size, _size);
sprite.Brush = fxBrush;
ElementCompositionPreview.SetElementChildVisual(this, sprite);
}
private void MainPage_PointerMoved(object sender, PointerRoutedEventArgs e)
{
var position = e.GetCurrentPoint(this).Position.ToVector2();
_maskSurfaceBrush.Offset = position - new Vector2(_size / 2, _size / 2);
}
比以往任何时候都更好用!