Aracılığıyla paylaş


SkiaSharp gürültü ve kompostlama

Basit vektör grafikleri doğaya aykırı görünme eğilimindedir. Düz çizgiler, düz eğriler ve düz renkler gerçek dünyadaki nesnelerin kusurlarına benzemez. 1982 filmi Tron için bilgisayar tarafından oluşturulan grafikler üzerinde çalışırken, bilgisayar bilimcisi Ken Perlin bu görüntülere daha gerçekçi dokular sağlamak için rastgele işlemler kullanan algoritmalar geliştirmeye başladı. 1997'de Ken Perlin, Teknik Başarı Akademi Ödülü'nü kazandı. Çalışmaları Perlin gürültüsü olarak bilinir ve SkiaSharp'ta desteklenir. Bir örnek aşağıda verilmiştir:

Perlin Kirlilik örneği

Gördüğünüz gibi her piksel rastgele bir renk değeri değildir. Pikselden piksele süreklilik rastgele şekillerle sonuçlanır.

Skia'da Perlin gürültüsü desteği, CSS ve SVG için W3C belirtimini temel alır. Filtre Efektleri Modül Düzey 1'in 8.20. bölümü, C kodunda temel alınan Perlin kirlilik algoritmalarını içerir.

Perlin gürültüsünü keşfetme

sınıfı, SKShader Perlin gürültüsü oluşturmak için iki farklı statik yöntem tanımlar: CreatePerlinNoiseFractalNoise ve CreatePerlinNoiseTurbulence. Parametreler aynıdır:

public static SkiaSharp CreatePerlinNoiseFractalNoise (float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed);

public static SkiaSharp.SKShader CreatePerlinNoiseTurbulence (float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed);

Her iki yöntem de ek SKPointI bir parametreyle aşırı yüklenmiş sürümlerde bulunur. Tiling Perlin noise bölümünde bu aşırı yüklemeler ele alınmaktadır.

İki baseFrequency bağımsız değişken, SkiaSharp belgelerinde 0 ile 1 arasında tanımlanan pozitif değerlerdir, ancak daha yüksek değerlere de ayarlanabilir. Değer ne kadar yüksekse, yatay ve dikey yönlerde rastgele görüntüdeki değişiklik de o kadar büyük olacaktır.

Değer numOctaves 1 veya daha yüksek bir tamsayıdır. Algoritmalardaki yineleme faktörüyle ilgilidir. Her ek oktav, önceki sekizlinin yarısı olan bir etkiye katkıda bulunur, bu nedenle daha yüksek oktav değerleriyle etki azalır.

seed parametresi, rastgele sayı oluşturucunun başlangıç noktasıdır. Kayan nokta değeri olarak belirtilse de, kesir kullanılmadan önce kesilir ve 0 değeri 1 ile aynıdır.

Örnekteki Perlin Kirlilik sayfası ve numOctaves bağımsız değişkenlerinin çeşitli değerleriyle baseFrequency denemeler yapmanızı sağlar. XAML dosyası şu şekildedir:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             x:Class="SkiaSharpFormsDemos.Effects.PerlinNoisePage"
             Title="Perlin Noise">

    <StackLayout>
        <skia:SKCanvasView x:Name="canvasView"
                           VerticalOptions="FillAndExpand"
                           PaintSurface="OnCanvasViewPaintSurface" />

        <Slider x:Name="baseFrequencyXSlider"
                Maximum="4"
                Margin="10, 0"
                ValueChanged="OnSliderValueChanged" />

        <Label x:Name="baseFrequencyXText"
               HorizontalTextAlignment="Center" />

        <Slider x:Name="baseFrequencyYSlider"
                Maximum="4"
                Margin="10, 0"
                ValueChanged="OnSliderValueChanged" />

        <Label x:Name="baseFrequencyYText"
               HorizontalTextAlignment="Center" />

        <StackLayout Orientation="Horizontal"
                     HorizontalOptions="Center"
                     Margin="10">

            <Label Text="{Binding Source={x:Reference octavesStepper},
                                  Path=Value,
                                  StringFormat='Number of Octaves: {0:F0}'}"
                   VerticalOptions="Center" />

            <Stepper x:Name="octavesStepper"
                     Minimum="1"
                     ValueChanged="OnStepperValueChanged" />
        </StackLayout>
    </StackLayout>
</ContentPage>

İki bağımsız değişken için iki Slider baseFrequency görünüm kullanır. Daha düşük değerlerin aralığını genişletmek için kaydırıcılar logaritmiktir. Arka planda kod dosyası, yöntemlerin bağımsız değişkenlerini SKShaderdeğerlerin Slider güçlerinden hesaplar. Görünümler Label hesaplanan değerleri görüntüler:

float baseFreqX = (float)Math.Pow(10, baseFrequencyXSlider.Value - 4);
baseFrequencyXText.Text = String.Format("Base Frequency X = {0:F4}", baseFreqX);

float baseFreqY = (float)Math.Pow(10, baseFrequencyYSlider.Value - 4);
baseFrequencyYText.Text = String.Format("Base Frequency Y = {0:F4}", baseFreqY);

Slider 1 değeri 0,001'e, Slider os 2 değeri 0,01'e, Slider 3 değerleri 0,1'e ve Slider 4 değeri 1'e karşılık gelir.

Bu kodu içeren arka planda kod dosyası aşağıdadır:

public partial class PerlinNoisePage : ContentPage
{
    public PerlinNoisePage()
    {
        InitializeComponent();
    }

    void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
    {
        canvasView.InvalidateSurface();
    }

    void OnStepperValueChanged(object sender, ValueChangedEventArgs args)
    {
        canvasView.InvalidateSurface();
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        // Get values from sliders and stepper
        float baseFreqX = (float)Math.Pow(10, baseFrequencyXSlider.Value - 4);
        baseFrequencyXText.Text = String.Format("Base Frequency X = {0:F4}", baseFreqX);

        float baseFreqY = (float)Math.Pow(10, baseFrequencyYSlider.Value - 4);
        baseFrequencyYText.Text = String.Format("Base Frequency Y = {0:F4}", baseFreqY);

        int numOctaves = (int)octavesStepper.Value;

        using (SKPaint paint = new SKPaint())
        {
            paint.Shader =
                SKShader.CreatePerlinNoiseFractalNoise(baseFreqX,
                                                       baseFreqY,
                                                       numOctaves,
                                                       0);

            SKRect rect = new SKRect(0, 0, info.Width, info.Height / 2);
            canvas.DrawRect(rect, paint);

            paint.Shader =
                SKShader.CreatePerlinNoiseTurbulence(baseFreqX,
                                                     baseFreqY,
                                                     numOctaves,
                                                     0);

            rect = new SKRect(0, info.Height / 2, info.Width, info.Height);
            canvas.DrawRect(rect, paint);
        }
    }
}

iOS, Android ve Evrensel Windows Platformu (UWP) cihazlarında çalışan program aşağıdadır. Fraktal gürültü tuvalin üst yarısında gösterilir. Türbülans gürültüsü alt yarıdadır:

Perlin Gürültüsü

Aynı bağımsız değişkenler her zaman sol üst köşeden başlayan deseni üretir. UWP penceresinin genişliğini ve yüksekliğini ayarladığınızda bu tutarlılık açıktır. Windows 10 ekranı yeniden çizdikçe, tuvalin üst yarısındaki desen aynı kalır.

Gürültü deseni çeşitli saydamlık derecelerini içerir. Çağrıda canvas.Clear() bir renk ayarlarsanız saydamlık belirginleşir. Bu renk desende belirginleşir. Bu etkiyi, birden çok gölgelendiriciyi birleştirme bölümünde de görürsünüz.

Bu Perlin gürültü desenleri nadiren kendileri tarafından kullanılır. Genellikle daha sonraki makalelerde ele alınan karışım modlarına ve renk filtrelerine tabi tutulurlar.

Döşeme Perlin gürültüsü

Perlin gürültüsü oluşturmak için iki statik SKShader yöntem, aşırı yükleme sürümlerinde de mevcuttur. CreatePerlinNoiseFractalNoise ve CreatePerlinNoiseTurbulence aşırı yüklemelerinin ek SKPointI bir parametresi vardır:

public static SKShader CreatePerlinNoiseFractalNoise (float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, SKPointI tileSize);

public static SKShader CreatePerlinNoiseTurbulence (float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, SKPointI tileSize);

Yapı SKPointI , tanıdık SKPoint yapının tamsayı sürümüdür. SKPointIyerine türü int floatve Y özelliklerini tanımlarX.

Bu yöntemler, belirtilen boyutta yinelenen bir desen oluşturur. Her kutucukta sağ kenar sol kenarla, üst kenar ise alt kenarla aynıdır. Bu özellik, Döşemeli Perlin Kirliliği sayfasında gösterilmiştir. XAML dosyası önceki örneğe benzer, ancak yalnızca bağımsız değişkeni değiştirmek seed için bir Stepper görünümü vardır:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             x:Class="SkiaSharpFormsDemos.Effects.TiledPerlinNoisePage"
             Title="Tiled Perlin Noise">

    <StackLayout>
        <skia:SKCanvasView x:Name="canvasView"
                           VerticalOptions="FillAndExpand"
                           PaintSurface="OnCanvasViewPaintSurface" />

        <StackLayout Orientation="Horizontal"
                     HorizontalOptions="Center"
                     Margin="10">

            <Label Text="{Binding Source={x:Reference seedStepper},
                                  Path=Value,
                                  StringFormat='Seed: {0:F0}'}"
                   VerticalOptions="Center" />

            <Stepper x:Name="seedStepper"
                     Minimum="1"
                     ValueChanged="OnStepperValueChanged" />

        </StackLayout>
    </StackLayout>
</ContentPage>

Arka planda kod dosyası, kutucuk boyutu için bir sabit tanımlar. İşleyici, PaintSurface bu boyutta bir bit eşlem ve bu bit eşlem içine çizim için bir SKCanvas oluşturur. yöntemi, SKShader.CreatePerlinNoiseTurbulence bu kutucuk boyutuna sahip bir gölgelendirici oluşturur. Bu gölgelendirici bit eşlem üzerine çizilir:

public partial class TiledPerlinNoisePage : ContentPage
{
    const int TILE_SIZE = 200;

    public TiledPerlinNoisePage()
    {
        InitializeComponent();
    }

    void OnStepperValueChanged(object sender, ValueChangedEventArgs args)
    {
        canvasView.InvalidateSurface();
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        // Get seed value from stepper
        float seed = (float)seedStepper.Value;

        SKRect tileRect = new SKRect(0, 0, TILE_SIZE, TILE_SIZE);

        using (SKBitmap bitmap = new SKBitmap(TILE_SIZE, TILE_SIZE))
        {
            using (SKCanvas bitmapCanvas = new SKCanvas(bitmap))
            {
                bitmapCanvas.Clear();

                // Draw tiled turbulence noise on bitmap
                using (SKPaint paint = new SKPaint())
                {
                    paint.Shader = SKShader.CreatePerlinNoiseTurbulence(
                                        0.02f, 0.02f, 1, seed,
                                        new SKPointI(TILE_SIZE, TILE_SIZE));

                    bitmapCanvas.DrawRect(tileRect, paint);
                }
            }

            // Draw tiled bitmap shader on canvas
            using (SKPaint paint = new SKPaint())
            {
                paint.Shader = SKShader.CreateBitmap(bitmap,
                                                     SKShaderTileMode.Repeat,
                                                     SKShaderTileMode.Repeat);
                canvas.DrawRect(info.Rect, paint);
            }

            // Draw rectangle showing tile
            using (SKPaint paint = new SKPaint())
            {
                paint.Style = SKPaintStyle.Stroke;
                paint.Color = SKColors.Black;
                paint.StrokeWidth = 2;

                canvas.DrawRect(tileRect, paint);
            }
        }
    }
}

Bit eşlem oluşturulduktan sonra, çağrılarak SKShader.CreateBitmapkutucuklu bit eşlem deseni oluşturmak için başka bir SKPaint nesne kullanılır. öğesinin iki bağımsız değişkenine SKShaderTileMode.Repeatdikkat edin:

paint.Shader = SKShader.CreateBitmap(bitmap,
                                     SKShaderTileMode.Repeat,
                                     SKShaderTileMode.Repeat);

Bu gölgelendirici tuvali kaplamak için kullanılır. Son olarak, özgün bit eşlemin boyutunu gösteren bir dikdörtgeni vuruş yapmak için başka bir SKPaint nesne kullanılır.

seed Kullanıcı arabiriminden yalnızca parametresi seçilebilir. Her platformda aynı seed desen kullanılırsa, aynı desen gösterilir. Farklı seed değerler farklı desenlerle sonuçlanır:

Döşemeli Perlin Gürültüsü

Sol üst köşedeki 200 piksel kare deseni diğer kutucuklara sorunsuz bir şekilde akar.

Birden çok gölgelendiriciyi birleştirme

sınıfı, SKShader belirtilen düz renge sahip bir gölgelendirici oluşturan bir yöntem içerir CreateColor . Bu gölgelendirici tek başına çok kullanışlı değildir çünkü bu rengi nesnenin Color SKPaint özelliğine ayarlayabilir ve özelliğini null olarak ayarlayabilirsiniz Shader .

Bu CreateColor yöntem, tanımlayan başka bir yöntemde SKShader yararlı olur. Bu yöntem, iki gölgelendiriciyi birleştiren yöntemidir CreateCompose. Söz dizimi şöyledir:

public static SKShader CreateCompose (SKShader dstShader, SKShader srcShader);

srcShader (Kaynak gölgelendirici) etkin bir şekilde üzerine dstShader çizilir (hedef gölgelendirici). Kaynak gölgelendirici düz bir renkse veya saydamlığı olmayan bir gradyansa, hedef gölgelendirici tamamen gizlenecektir.

Perlin gürültü gölgelendiricisi saydamlık içerir. Kaynak bu gölgelendiriciyse, hedef gölgelendirici saydam alanlarda gösterilir.

Oluşturulan Perlin Kirliliği sayfasında, ilk Perlin Kirliliği sayfasıyla neredeyse aynı olan bir XAML dosyası vardır. Arka planda kod dosyası da benzerdir. Ancak özgün Perlin Kirlilik sayfası özelliğini SKPaint statik CreatePerlinNoiseFractalNoise ve CreatePerlinNoiseTurbulence yöntemlerden döndürülen gölgelendiriciye ayarlarShader. Bu Composed Perlin Noise sayfası, karma gölgelendiriciyi çağırır CreateCompose . Hedef, kullanılarak CreateColoroluşturulan düz mavi gölgelendiricidir. Kaynak bir Perlin gürültü gölgelendiricisi:

public partial class ComposedPerlinNoisePage : ContentPage
{
    public ComposedPerlinNoisePage()
    {
        InitializeComponent();
    }

    void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
    {
        canvasView.InvalidateSurface();
    }

    void OnStepperValueChanged(object sender, ValueChangedEventArgs args)
    {
        canvasView.InvalidateSurface();
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        // Get values from sliders and stepper
        float baseFreqX = (float)Math.Pow(10, baseFrequencyXSlider.Value - 4);
        baseFrequencyXText.Text = String.Format("Base Frequency X = {0:F4}", baseFreqX);

        float baseFreqY = (float)Math.Pow(10, baseFrequencyYSlider.Value - 4);
        baseFrequencyYText.Text = String.Format("Base Frequency Y = {0:F4}", baseFreqY);

        int numOctaves = (int)octavesStepper.Value;

        using (SKPaint paint = new SKPaint())
        {
            paint.Shader = SKShader.CreateCompose(
                SKShader.CreateColor(SKColors.Blue),
                SKShader.CreatePerlinNoiseFractalNoise(baseFreqX,
                                                       baseFreqY,
                                                       numOctaves,
                                                       0));

            SKRect rect = new SKRect(0, 0, info.Width, info.Height / 2);
            canvas.DrawRect(rect, paint);

            paint.Shader = SKShader.CreateCompose(
                SKShader.CreateColor(SKColors.Blue),
                SKShader.CreatePerlinNoiseTurbulence(baseFreqX,
                                                     baseFreqY,
                                                     numOctaves,
                                                     0));

            rect = new SKRect(0, info.Height / 2, info.Width, info.Height);
            canvas.DrawRect(rect, paint);
        }
    }
}

Fraktal gürültü gölgelendiricisi üsttedir; türbülans gölgelendiricisi alttadır:

Oluşturulan Perlin Gürültüsü

Bu gölgelendiricilerin Perlin Gürültü sayfası tarafından görüntülenenlerden ne kadar daha mavi olduğunu görebilirsiniz. Bu fark, gürültü gölgelendiricilerindeki saydamlık miktarını gösterir.

Yönteminin aşırı yüklemesi CreateCompose de vardır:

public static SKShader CreateCompose (SKShader dstShader, SKShader srcShader, SKBlendMode blendMode);

Son parametre, SkiaSharp birleştirme ve harmanlama modları ile ilgili sonraki makale dizisinde ele alınan 29 üyeli bir numaralandırma olan numaralandırmanın bir üyesidirSKBlendMode.