CG Library SkiaSharp「Wire frame」

::: note
- WebのAI機能使って作成。殆どコピペ。
- 陰面処理してませんので見てるうちに分からなくなってくる。
- 初期の3DCGはテクスチャの無いワイヤーフレームで83年頃のアタリ社のStar Warsというワイヤーフレームのアーケードゲームに熱中した覚え有り。タワーが地中から伸びてくるシーンにビックリ。他にはBattlezone等。
:::

#### 1.動画
<iframe width="1001" height="565" src="https://www.youtube.com/embed/HM2t8LAw_Ng" title="WPF + Skiasharp (wire frame)" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

#### 2.WPF
``` c#
////////////////////////////////
// WPF+SkiaSharp ワイヤーフレーム
////////////////////////////////

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

namespace WireframeWpf{

    public partial class MainWindow : Window{

        private SKPoint3[] vertices;
        private (int, int)[] edges;
        private float angle = 0;

        public MainWindow()        {
            InitializeComponent();

            vertices = new SKPoint3[]{
                new SKPoint3(-1, -1, -1),
                new SKPoint3(1, -1, -1),
                new SKPoint3(1, 1, -1),
                new SKPoint3(-1, 1, -1),
                new SKPoint3(-1, -1, 1),
                new SKPoint3(1, -1, 1),
                new SKPoint3(1, 1, 1),
                new SKPoint3(-1, 1, 1)
            };

            edges = new (int, int)[] {
                (0,1),(1,2),(2,3),(3,0),
                (4,5),(5,6),(6,7),(7,4),
                (0,4),(1,5),(2,6),(3,7)
            };

            var timer = new DispatcherTimer {
                Interval = TimeSpan.FromMilliseconds(2)
            };

            timer.Tick += (s, e) => {
                angle += 0.01f;
                SkElement.InvalidateVisual();
            };

            timer.Start();
        }

        private SKPoint3 RotateY(SKPoint3 p, float angle) {
            float cosA = (float)Math.Cos(angle);
            float sinA = (float)Math.Sin(angle);
            return new SKPoint3(
                p.X * cosA - p.Z * sinA,
                p.Y,
                p.X * sinA + p.Z * cosA
            );
        }

        private SKPoint Project(SKPoint3 p, float width, float height, float fov, float viewerDistance) {
            float factor = fov / (viewerDistance + p.Z);
            float x = p.X * factor + width / 2;
            float y = -p.Y * factor + height / 2;
            return new SKPoint(x, y);
        }

        private void SkElement_PaintSurface(object sender, SKPaintSurfaceEventArgs e){
            var canvas = e.Surface.Canvas;
            var info = e.Info;

            canvas.Clear(SKColors.Black);

            SKPoint3[] rotated = new SKPoint3[vertices.Length];

            for (int i = 0; i < vertices.Length; i++){
                rotated[i] = RotateY(vertices[i], angle);
            }

            var paint = new SKPaint {
                Color = SKColors.Blue,
                StrokeWidth = 3,
                IsStroke = true,
                IsAntialias = true
            };

            foreach (var (start, end) in edges){
                var p1 = Project(rotated[start], info.Width, info.Height, 256, 3);
                var p2 = Project(rotated[end], info.Width, info.Height, 256, 3);
                canvas.DrawLine(p1, p2, paint);
            }
        }
    }
}
```

#### 3.XAML
``` xml
<Window x:Class="WireframeWpf.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:WireframeWpf"
        mc:Ignorable="d"
        xmlns:skia="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF"
        Title="SkiaSharp Wireframe 3D" Height="450" Width="800">
      
    <Grid>
        <skia:SKElement x:Name="SkElement" PaintSurface="SkElement_PaintSurface" />
    </Grid>
</Window>
```