question

Sal-Datoccio avatar image
0 Votes"
Sal-Datoccio asked JarvanZhang-MSFT commented

SkiaSharp/Skia - Rotating shapes around their own axis

I am learning SkiaSharp and I'd like to have N shapes rotating around their own vertical axis, but I can't find a way to do it.

This is the result of my OnDraw method (rotationView is updated every N milliseconds):

80047-cho7x.png

  protected override void OnDraw(SKCanvas canvas, int width, int height)
     {
         int i = 0;
         int step = 0;
         List<SKRect> rects = new List<SKRect>();
    
         // get the 2D equivalent of the 3D matrix
         var rotationMatrix = rotationView.Matrix;
    
         // get the properties of the rectangle
         var length = Math.Min(width / 6, height / 6);
    
         canvas.Clear(EffectMedia.Colors.XamarinLightBlue);
    
         foreach (var n in numbers)
         {
             var rect = new SKRect(0 + step, 0, 100 + step, 100);
             rects.Add(rect);
             step += 120;
         }
    
         //var sideHoriz = rotationMatrix.MapPoint(new SKPoint(0, 1)).Y > 0;
         var sideVert = rotationMatrix.MapPoint(new SKPoint(1, 0)).X > 0;
    
         var paint = new SKPaint
         {
             Color = sideVert ? EffectMedia.Colors.XamarinPurple : EffectMedia.Colors.XamarinGreen,
             Style = SKPaintStyle.Fill,
             IsAntialias = true
         };
    
         // first do 2D translation to the center of the screen
         canvas.Translate((width - (120 * numbers.Count)) / 2, height / 2);
    
         // The following line is disabled because it makes the whole canvas rotate!
         // canvas.Concat(ref rotationMatrix);
    
         foreach (var n in numbers)
         {            
             canvas.RotateDegrees((float)-3);
             canvas.DrawRoundRect(rects[i], 30, 30, paint);
    
             var shadow = SKShader.CreateLinearGradient(
                     new SKPoint(0, 0), new SKPoint(0, length * 2),
                     new[] { paint.Color.WithAlpha(127), paint.Color.WithAlpha(0) },
                     null,
                     SKShaderTileMode.Clamp);
    
             var paintShadow = new SKPaint
             {
                 Shader = shadow,
                 Style = SKPaintStyle.Fill,
                 IsAntialias = true,
                 BlendMode = SKBlendMode.SoftLight
             };
    
             foreach (var r in rects)
             {
                 r.Offset(0, 105);
                 canvas.DrawRoundRect(r, 30, 30, paintShadow);
             }
    
             i++;
         }
     }


I tried using SKPath + Transform, saving&restoring the rotationMatrix and/or the canvas but I can't find a way to have 6 rotating boxes around their own axis.

Do you have any hint on how that can be achieved? Do I need N rotation matrices?

Thanks!

dotnet-xamarinformswindows-wpfdotnet-xamarinessentials
cho7x.png (53.5 KiB)
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi, Sal-Datoccio. The animation you want is hard to develop this SKMatrix transform working solely within two dimensions, try using 3d animation instead. You could check the following the doc to get the details about the function.
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/transforms/3d-rotation

Here is the related sample code, you could refer to it.
https://github.com/xamarin/xamarin-forms-samples/blob/master/SkiaSharpForms/Demos/Demos/SkiaSharpFormsDemos/Transforms/AnimatedRotation3DPage.cs

1 Vote 1 ·

Thank you!

I am going to check the AnimatedRotation3DPage demo, for now I am able to rotate those figures around their own Z-axis with:

canvas.Save();
canvas.RotateDegrees(degrees, rects[i].MidX, rects[i].MidY);
canvas.DrawRoundRect(rects[i], 30, 30, paint);
canvas.Restore();

I was also using a Skia3DView, but I can't manage to make it work without rotating the whole canvas. I also tried with paths and related transforms, with no luck.

I'll have a look at https://github.com/xamarin/xamarin-forms-samples/blob/master/SkiaSharpForms/Demos/Demos/SkiaSharpFormsDemos/Transforms/AnimatedRotation3DPage.cs

Thanks

`

0 Votes 0 ·
Sal-Datoccio avatar image
0 Votes"
Sal-Datoccio answered

My goal would be to have N shapes rotating around their axes, something like:

80080-untitled.png



Would could be a viable approach in SkiaSharp (I'd just need some directions)?

Thanks :)


untitled.png (67.8 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

JarvanZhang-MSFT avatar image
0 Votes"
JarvanZhang-MSFT answered JarvanZhang-MSFT commented

Hi, Sal-Datoccio. According to my search, it doesn't provide a way to get the drawing sharp. A workaround is using SKCanvasView to draw each sharp one separately, and rotate the skCanvasViews.

Here is the related code, you could refer to it.

public partial class TestPage : ContentPage
{
    public TestPage()
    {
        Title = "Testing for Animated Rotation";

        canvasView1 = new SKCanvasView() { AutomationId = "1" };
        canvasView2 = new SKCanvasView() { AutomationId = "2" };
        canvasView3 = new SKCanvasView() { AutomationId = "3" };
        canvasView4 = new SKCanvasView() { AutomationId = "4" };
        canvasView5 = new SKCanvasView() { AutomationId = "5" };
        canvasView6 = new SKCanvasView() { AutomationId = "6" };

        canvasView1.PaintSurface += OnCanvasViewPaintSurface;
        canvasView2.PaintSurface += OnCanvasViewPaintSurface;
        canvasView3.PaintSurface += OnCanvasViewPaintSurface;
        canvasView4.PaintSurface += OnCanvasViewPaintSurface;
        canvasView5.PaintSurface += OnCanvasViewPaintSurface;
        canvasView6.PaintSurface += OnCanvasViewPaintSurface;
        Content = new StackLayout()
        {
            HorizontalOptions = LayoutOptions.Center,
            Orientation = StackOrientation.Horizontal,
            Children = { canvasView1, canvasView2, canvasView3, canvasView4, canvasView5, canvasView6 }
        };

        // Measure the text
        textPaint.MeasureText(text1, ref textBounds);
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();

        new Animation((value) =>
        {
            yRotationDegrees = 360 * (float)value;
            canvasView1.InvalidateSurface();
            canvasView2.InvalidateSurface();
            canvasView3.InvalidateSurface();
            canvasView4.InvalidateSurface();
            canvasView5.InvalidateSurface();
            canvasView6.InvalidateSurface();
        }).Commit(this, "yRotationAnimation", length: 1000, repeat: () => true);
    }
    protected override void OnDisappearing()
    {
        base.OnDisappearing();
        //this.AbortAnimation("xRotationAnimation");
        this.AbortAnimation("yRotationAnimation");
        //this.AbortAnimation("zRotationAnimation");
    }
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        // Find center of canvas
        float xCenter = info.Width / 2;
        float yCenter = info.Height / 2;

        // Translate center to origin
        SKMatrix matrix = SKMatrix.MakeTranslation(-xCenter, -yCenter);

        float scale = 1;
        SKMatrix.PostConcat(ref matrix, SKMatrix.MakeScale(scale, scale));

        // Calculate composite 3D transforms
        float depth = 0.75f * scale * textBounds.Width;

        SKMatrix44 matrix44 = SKMatrix44.CreateIdentity();
        //matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(1, 0, 0, xRotationDegrees));
        matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(0, 1, 0, yRotationDegrees));
        //matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(0, 0, 1, zRotationDegrees));

        SKMatrix44 perspectiveMatrix = SKMatrix44.CreateIdentity();
        perspectiveMatrix[3, 2] = -1 / depth;
        matrix44.PostConcat(perspectiveMatrix);

        // Concatenate with 2D matrix
        SKMatrix.PostConcat(ref matrix, matrix44.Matrix);

        // Translate back to center
        SKMatrix.PostConcat(ref matrix,
            SKMatrix.MakeTranslation(xCenter, yCenter));

        // Set the matrix and display the text
        canvas.SetMatrix(matrix);
        float xText = xCenter - textBounds.MidX;
        float yText = yCenter - textBounds.MidY;

        SKCanvasView view = sender as SKCanvasView;
        switch (view.AutomationId)
        {
            case "1":
                canvas.DrawText(text1, xText, yText, textPaint);
                break;
            case "2":
                canvas.DrawText(text2, xText, yText, textPaint);
                break;
            case "3":
                canvas.DrawText(text3, xText, yText, textPaint);
                break;
            case "4":
                canvas.DrawText(text4, xText, yText, textPaint);
                break;
            case "5":
                canvas.DrawText(text5, xText, yText, textPaint);
                break;
            case "6":
                canvas.DrawText(text6, xText, yText, textPaint);
                break;
        }
    }
}





· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

The related parameters of the above page.

SKCanvasView canvasView1;
SKCanvasView canvasView2;
SKCanvasView canvasView3;
SKCanvasView canvasView4;
SKCanvasView canvasView5;
SKCanvasView canvasView6;

float yRotationDegrees;

string text1 = "S";
string text2 = "k";
string text3 = "S";
string text4 = "h";
string text5 = "r";
string text6 = "p";

SKPaint textPaint = new SKPaint
{
    Style = SKPaintStyle.Stroke,
    Color = SKColors.Black,
    TextSize = 100,
    StrokeWidth = 3,
};
SKRect textBounds;
0 Votes 0 ·