CG Library SkiaSharp「3Dアニメーション」

<B>
<font COLOR="blue" >
・~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~・<BR>
・グラフィックスライブラリ、SkiaSharpのSKMatrix44クラスを使用し、<br>
・非アフェン変換を行い立体化させパラメータを連続可変させてアニメーション化します。<BR>
・~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~・<BR>
</B>

1.マーク・フリント氏による伝説のOP(83年)の再現のスクリーンショット 40年ぶりに蘇る
![B.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821882/ed672413-8c88-0045-c18e-72f5aaec3a1b.jpeg)
2.WQHD(2540x1440)での動画(キャプチャ中でFPS下がってます)。他、10年前のノートPCでもそれなりに動きました。

<iframe width="560" height="315" src="https://www.youtube.com/embed/CygWGgepBPM?si=08g0p4cn1AkU3cUh" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>


- 作ってて結局わからず放置してたが<a href="https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/transforms/3d-rotation">サンプル</A>を見つけそれを改変しました。
- SKMatrixが古い等と警告でますがメークは通ります。
- 手製のプログラムに内蔵して演出させたらどうでしょう。パラメータ変えると色々表示が変わります。
- 元来、2D専用と言う事もあり厚みがありません。
- その昔、x86でグラフィックディスプレイコントローラ(μPD7220)直叩きで3Dやってたのに今や高級言語で出来ちゃう時代。


### <font  color="6495ed">1.XYZ軸回転しながら近づいてまた遠方へ</F>
漢字用 LINEフォント入れてない場合はTypeface = SKTypeface.FromFamilyName("LINE Seed JP_OTF"),　を削除。
```c#
// SkiaSharp Test / inf102
// https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/transforms/3d-rotation

using SkiaSharp;
using SkiaSharp.Views.Desktop;
using System;
using System.Threading.Tasks;
using System.Windows;

namespace SkiaSharpSample {

    public partial class MainWindow : Window	{

        static int r=0;//2000;
        static float s=0;//=23;
        static bool flg;
        static string[] st = {   "SKIA SHARP&SKMatrix44","三次元ｱﾆﾒｰｼｮﾝ映像", "3D VALIANT", "ThreeDimensions","Smooth 3D Video" };
        static int stn = 0;

		public MainWindow()		{
			InitializeComponent();
            this.WindowState = WindowState.Maximized;
		}

        private async  void Window_Loaded(object sender, RoutedEventArgs e) {

            while (true){
                skiaCanvas2.InvalidateVisual(); 

               // Title = r + "s="+s;

                if (r == 632)  stn = 1;
                if (r == 1345) stn = 2;
                if (r == 2427) stn = 3; 
                if (r == 2249 && flg == true) stn = 4;
                                
                if (r>=3000) {
                    flg =true;
                }

                if (r<=0 || s<=0 ) {
                    flg=false;
                    r=0;
                }

                // 大きく
                if (flg == false) {
               
                    r++;
                    s=s+(float)0.01; // SIZE
                }
                // 小さくする
                else {
                 
                    r--;
                    s=s-(float)0.03;
                }

                await Task.Delay (1); //2000 23
                 
            }
        }


		void PaintSurface(object sender, SKPaintSurfaceEventArgs args){

            SKImageInfo info = args.Info;
            SKSurface surface = args.Surface;
            SKCanvas canvas = surface.Canvas;

            canvas.Clear(SKColors.Black);

            SKPaint textPaint = new SKPaint{
                Style = SKPaintStyle.Fill,
                Color = SKColors.Yellow,
                IsAntialias=true,
                LcdRenderText=true,
                FakeBoldText = true,
                TextSize = s,
                TextAlign= (SKTextAlign)SKTextAlign.Center,
                Typeface = SKTypeface.FromFamilyName("LINE Seed JP_OTF"),
                //TextSkewX=2, // 斜め
                //TextScaleX = 3f // 圧縮
            };

            if(stn == 1) textPaint.Color = new SKColor(0, 255, 0);
            if(stn == 2) textPaint.Color = new SKColor(0, 00, 255);

            // 色を変える場合
            Random Rnd = new Random();
            if (flg) textPaint.Color=new SKColor((byte)Rnd.Next(0, 255), (byte)Rnd.Next(0, 255),(byte)Rnd.Next(0, 255));

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

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

            // Scale so text fits
            float scale = Math.Min(info.Width / 110,info.Height / 110);
            SKMatrix.PostConcat(ref matrix, SKMatrix.MakeScale(scale, scale));

            // Calculate composite 3D transforms
            float depth = 0.75f * scale * 100;
        
            SKMatrix44 matrix44 = SKMatrix44.CreateIdentity();
            matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(1, 0, 0, (float)r));   // 上下回転
            matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(0, 1, 0, (float)r));   // 左右回転
            matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(0, 0, 1, (float)r));   // 時計風回転

            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 - 3;
            float yText = yCenter + 5;

            canvas.DrawText(st[stn], xText, yText, textPaint);

        }

	}
}
```
### <font  color="6495ed">2.Y軸のみ回転</F>
```c#
// SkiaSharp Test / Y軸回転
// https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/transforms/3d-rotation

using SkiaSharp;
using SkiaSharp.Views.Desktop;
using System;
using System.Threading.Tasks;
using System.Windows;

namespace SkiaSharpSample {

    public partial class MainWindow : Window	{

        static int r=0;
        static float s=2;
        static bool flg=false;
        static string text="";

		public MainWindow()		{
			InitializeComponent();
            this.WindowState = WindowState.Maximized;
		}

        private async  void Window_Loaded(object sender, RoutedEventArgs e) {

            // 1st
            text="3D VALIANT";

            while (true){
                skiaCanvas2.InvalidateVisual();

                Title = s.ToString();

                if (  s>=(float)30.06483  && flg==false) {
                    s=14;
                    r=0;
                    flg=true;
                    text="WPF+SkiaSharp"; //2nd
                }

                r++; // 回転
                s=s+(float)0.015; // SIZE
                
                await Task.Delay(1); 
                 
            }
        }


		void PaintSurface(object sender, SKPaintSurfaceEventArgs args){

            SKImageInfo info = args.Info;
            SKSurface surface = args.Surface;
            SKCanvas canvas = surface.Canvas;

            canvas.Clear(SKColors.Black);

            SKPaint textPaint = new SKPaint{
                Style = SKPaintStyle.Fill,
                IsAntialias=true,
                LcdRenderText=true,
                TextSize = s,
       
                TextAlign= (SKTextAlign)SKTextAlign.Center,
           
                //    Typeface = SKTypeface.FromFamilyName("LINE Seed JP_OTF"),
  
            };

            if(flg == false) textPaint.Color = new SKColor(0, 255,127);
            else textPaint.Color = new SKColor(255, 218,185);

            // 色を変える場合
            Random Rnd = new Random();
          //  textPaint.Color=new SKColor((byte)Rnd.Next(0, 255), (byte)Rnd.Next(0, 255),(byte)Rnd.Next(0, 255));

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

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

            // Scale so text fits
            float scale = Math.Min(info.Width / 110,info.Height / 110);
            SKMatrix.PostConcat(ref matrix, SKMatrix.MakeScale(scale, scale));

            // Calculate composite 3D transforms
            float depth = 0.75f * scale * 100;
            SKMatrix44 matrix44 = SKMatrix44.CreateIdentity();
            matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(0, 1, 0, (float)r));   
          //  if (flg==true){
             //   matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(0, 0, 1, (float)r));   
           //     matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(1, 0, 0, (float)r));
          //  }

            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 - 0;  //回転軸
            float yText = yCenter + 9;  //縦位置

            canvas.DrawText(text, xText, yText+1, textPaint);
  
        }
	}
}
```



### <font  color="6495ed">3.XAML (共通)</F>
```xml
<Window x:Class="SkiaSharpSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SkiaSharpSample" xmlns:skia="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF" 
        xmlns:wpf="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF" mc:Ignorable="d"
        Title="SkiaSharp" Loaded="Window_Loaded" Height="850" Width="850" >

    <Grid  >

        <wpf:SKElement x:Name="skiaCanvas2" PaintSurface="PaintSurface"  />
    </Grid>

</Window>
```