Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Ponořte se hlouběji do transformací SkiaSharp s univerzální transformační maticí
Všechny transformace použité na SKCanvas objekt jsou sloučeny v jedné instanci SKMatrix struktury. Jedná se o standardní 3-by-3 transformační matici podobnou těm ve všech moderních 2D grafických systémech.
Jak jste viděli, můžete použít transformace ve SkiaSharpu, aniž byste věděli o matici transformace, ale matice transformace je důležitá z teoretické perspektivy a je zásadní při použití transformací k úpravě cest nebo pro zpracování komplexního dotykového vstupu, z nichž obě jsou demonstrované v tomto článku i v dalším článku.

Aktuální transformační matice použitá na tuto SKCanvas hodnotu je kdykoli dostupná přístupem k vlastnosti jen TotalMatrix pro čtení. Pomocí metody můžete nastavit novou transformační matici SetMatrix a tuto matici můžete obnovit na výchozí hodnoty voláním ResetMatrix.
Jediný další SKCanvas člen, který přímo pracuje s transformací matice plátna, je Concat ten, který zřetězí dvě matice tím, že je vynásobí dohromady.
Výchozí transformační matice je matice identity, která se skládá z 1 v diagonálních buňkách a 0 všude jinde:
| 1 0 0 | | 0 1 0 | | 0 0 1 |
Matici identit můžete vytvořit pomocí statické SKMatrix.MakeIdentity metody:
SKMatrix matrix = SKMatrix.MakeIdentity();
Výchozí SKMatrix konstruktor nevracímatici identity. Vrátí matici se všemi buňkami nastavenými na nulu. Nepoužívejte SKMatrix konstruktor, pokud neplánujete tyto buňky nastavit ručně.
Když SkiaSharp vykresluje grafický objekt, každý bod (x, y) se efektivně převede na matici 1 po 3 s 1 ve třetím sloupci:
| x y 1 |
Tato matice 1 po 3 představuje trojrozměrný bod se souřadnicí Z nastavenou na hodnotu 1. Existují matematické důvody (probírané později), proč dvourozměrná transformace matice vyžaduje práci ve třech dimenzích. Tuto matici 1 by-3 si můžete představit jako bod v 3D souřadnicovém systému, ale vždy na 2D rovině, kde se Z rovná 1.
Tato matice 1:3 se pak vynásobí transformační maticí a výsledkem je bod vykreslený na plátně:
| 1 0 0 |
| x y 1 | × | 0 1 0 | = | x' y' z' |
| 0 0 1 |
Při použití standardního násobení matice jsou převedené body následující:
x' = x
y' = y
z' = 1
To je výchozí transformace.
Translate Když je volána metoda objektuSKCanvas, tx a ty argumenty metody Translate se stanou první dvě buňky ve třetím řádku transformační matice:
| 1 0 0 | | 0 1 0 | | tx ty 1 |
Násobení je teď následující:
| 1 0 0 |
| x y 1 | × | 0 1 0 | = | x' y' z' |
| tx ty 1 |
Tady jsou vzorce transformace:
x' = x + tx
y' = y + ty
Faktory škálování mají výchozí hodnotu 1. Při volání Scale metody pro nový SKCanvas objekt, výsledná transformační matice obsahuje sx a sy argumenty v diagonálních buňkách:
| sx 0 0 |
| x y 1 | × | 0 sy 0 | = | x' y' z' |
| 0 0 1 |
Vzorce transformace jsou následující:
x' = sx · x
y' = sy · y
Transformační matice po volání Skew obsahuje dva argumenty v buňkách matice sousedících s faktory škálování:
│ 1 ySkew 0 │
| x y 1 | × │ xSkew 1 0 │ = | x' y' z' |
│ 0 0 1 │
Vzorce transformace jsou:
x' = x + xSkew · y
y' = ySkew · x + y
V případě volání RotateDegrees nebo RotateRadians úhlu α je transformační matice následující:
│ cos(α) sin(α) 0 │
| x y 1 | × │ –sin(α) cos(α) 0 │ = | x' y' z' |
│ 0 0 1 │
Tady jsou vzorce transformace:
x' = cos(α) · x - sin(α) · y
y' = sin(α) · x - cos(α) · y
Když je α 0 stupňů, jedná se o matici identity. Pokud je α 180 stupňů, matice transformace je následující:
| –1 0 0 | | 0 –1 0 | | 0 0 1 |
Otočení o 180 stupňů je ekvivalentní překlopení objektu vodorovně a svisle, což se také provádí nastavením faktorů měřítka –1.
Všechny tyto typy transformací jsou klasifikovány jako affinové transformace. Transformace affinu nikdy nezahrnují třetí sloupec matice, který zůstává na výchozích hodnotách 0, 0 a 1. Článek Bez affinových transformací popisuje nefínové transformace.
Násobení matic
Jednou z významných výhod použití matice transformace je, že složené transformace lze získat pomocí násobení matice, která se často označuje v dokumentaci SkiaSharp jako zřetězení. Mnoho metod SKCanvas souvisejících s transformací odkazuje na "předběžné zřetězení" nebo "předběžné zřetězení". To odkazuje na pořadí násobení, což je důležité, protože násobení matice není kommutativní.
Například dokumentace pro metodu Translate říká, že "Předem zřetězí aktuální matici se zadaným překladem", zatímco dokumentace pro metodu Scale říká, že "Předem zřetězí aktuální matici se zadaným měřítkem".
To znamená, že transformace určená voláním metody je násobitel (levý operand) a aktuální transformační matice je násobený (operand zprava).
Předpokládejme, že Translate se volá a následuje Scale:
canvas.Translate(tx, ty);
canvas.Scale(sx, sy);
Transformace Scale se vynásobí Translate transformací pro složenou matici transformace:
| sx 0 0 | | 1 0 0 | | sx 0 0 | | 0 sy 0 | × | 0 1 0 | = | 0 sy 0 | | 0 0 1 | | tx ty 1 | | tx ty 1 |
Scale může být volána dříve, než Translate bude vypadat takto:
canvas.Scale(sx, sy);
canvas.Translate(tx, ty);
V takovém případě je pořadí násobení obrácené a faktory škálování se efektivně aplikují na faktory překladu:
| 1 0 0 | | sx 0 0 | | sx 0 0 | | 0 1 0 | × | 0 sy 0 | = | 0 sy 0 | | tx ty 1 | | 0 0 1 | | tx·sx ty·sy 1 |
Tady je Scale metoda s kontingenčním bodem:
canvas.Scale(sx, sy, px, py);
To odpovídá následujícím voláním překladu a škálování:
canvas.Translate(px, py);
canvas.Scale(sx, sy);
canvas.Translate(–px, –py);
Tři matice transformace se vynásobí v obráceném pořadí od toho, jak se metody zobrazují v kódu:
| 1 0 0 | | sx 0 0 | | 1 0 0 | | sx 0 0 | | 0 1 0 | × | 0 sy 0 | × | 0 1 0 | = | 0 sy 0 | | –px –py 1 | | 0 0 1 | | px py 1 | | px–px·sx py–py·sy 1 |
SkMatrix – struktura
Struktura SKMatrix definuje devět vlastností typu float pro čtení a zápis odpovídající devíti buňkám transformační matice:
│ ScaleX SkewY Persp0 │ │ SkewX ScaleY Persp1 │ │ TransX TransY Persp2 │
SKMatrix definuje také vlastnost s názvem Values typu float[]. Tuto vlastnost lze použít k nastavení nebo získání devíti hodnot v jednom snímku v pořadí ScaleX, , SkewX, TransX, SkewY, ScaleY, , TransY, , Persp0, , Persp1a Persp2.
Funkce , a buňky jsou popsány v článku Non-Affine Transforms.Persp2Persp1Persp0 Pokud mají tyto buňky výchozí hodnoty 0, 0 a 1, transformace se vynásobí souřadnicovým bodem takto:
│ ScaleX SkewY 0 │
| x y 1 | × │ SkewX ScaleY 0 │ = | x' y' z' |
│ TransX TransY 1 │
x' = ScaleX · x + SkewX · y + TransX
y' = SkewX · x + ScaleY · y + TransY
z' = 1
Toto je úplná dvojrozměrná affinová transformace. Transformace affine zachovává paralelní čáry, což znamená, že obdélník není nikdy transformován na nic jiného než paralelogram.
Struktura SKMatrix definuje několik statických metod pro vytvoření SKMatrix hodnot. Všechny tyto vrácené SKMatrix hodnoty:
MakeTranslationMakeScaleMakeScales bodem otáčeníMakeRotationpro úhel v radiánechMakeRotationpro úhel v radiánech s otočným bodemMakeRotationDegreesMakeRotationDegreess bodem otáčeníMakeSkew
SKMatrix definuje také několik statických metod, které zřetězí dvě matice, což znamená jejich násobení. Tyto metody jsou pojmenovány Concat, PostConcata PreConcat, a existují dvě verze každého. Tyto metody nemají žádné návratové hodnoty; místo toho odkazují na existující SKMatrix hodnoty prostřednictvím ref argumentů. V následujícím příkladu jsou Avšechny SKMatrix hodnoty , Ba R (pro "result").
Tyto dvě Concat metody se nazývají takto:
SKMatrix.Concat(ref R, A, B);
SKMatrix.Concat(ref R, ref A, ref B);
Tyto operace provádějí následující násobení:
R = B × A
Ostatní metody mají pouze dva parametry. První parametr je upraven a při návratu z volání metody obsahuje součin dvou matic. Tyto dvě PostConcat metody se nazývají takto:
SKMatrix.PostConcat(ref A, B);
SKMatrix.PostConcat(ref A, ref B);
Tato volání provádějí následující operaci:
A = A × B
PreConcat Dvě metody jsou podobné:
SKMatrix.PreConcat(ref A, B);
SKMatrix.PreConcat(ref A, ref B);
Tato volání provádějí následující operaci:
A = B × A
Verze těchto metod se všemi ref argumenty jsou mírně efektivnější při volání základních implementací, ale může být matoucí, že někdo přečte váš kód a za předpokladu, že metoda cokoli s ref argumentem upraví. Kromě toho je často vhodné předat argument, který je výsledkem jedné z Make metod, například:
SKMatrix result;
SKMatrix.Concat(result, SKMatrix.MakeTranslation(100, 100),
SKMatrix.MakeScale(3, 3));
Vytvoří se následující matice:
│ 3 0 0 │ │ 0 3 0 │ │ 100 100 1 │
Jedná se o transformaci škálování vynásobenou transformací překladu. V tomto konkrétním případě SKMatrix struktura poskytuje zástupce metody s názvem SetScaleTranslate:
SKMatrix R = new SKMatrix();
R.SetScaleTranslate(3, 3, 100, 100);
Toto je jednou z několikakrát, když je bezpečné používat SKMatrix konstruktor. Metoda SetScaleTranslate nastaví všech devět buněk matice. Je také bezpečné používat SKMatrix konstruktor se statickými Rotate metodami a RotateDegrees metodami:
SKMatrix R = new SKMatrix();
SKMatrix.Rotate(ref R, radians);
SKMatrix.Rotate(ref R, radians, px, py);
SKMatrix.RotateDegrees(ref R, degrees);
SKMatrix.RotateDegrees(ref R, degrees, px, py);
Tyto metody nezřetězení transformace otočení na existující transformaci. Metody nastaví všechny buňky matice. Jsou funkčně stejné jako MakeRotation metody a MakeRotationDegrees metody s tím rozdílem, že nedají vytvořit instanci SKMatrix hodnoty.
Předpokládejme, že máte SKPath objekt, který chcete zobrazit, ale dáváte přednost tomu, aby měl poněkud odlišnou orientaci nebo jiný středový bod. Všechny souřadnice této cesty můžete upravit voláním Transform metody SKPath s argumentem SKMatrix . Stránka Transformace cesty ukazuje, jak to provést. Třída PathTransform odkazuje na HendecagramPath objekt v poli, ale používá jeho konstruktor k použití transformace na tuto cestu:
public class PathTransformPage : ContentPage
{
SKPath transformedPath = HendecagramArrayPage.HendecagramPath;
public PathTransformPage()
{
Title = "Path Transform";
SKCanvasView canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
SKMatrix matrix = SKMatrix.MakeScale(3, 3);
SKMatrix.PostConcat(ref matrix, SKMatrix.MakeRotationDegrees(360f / 22));
SKMatrix.PostConcat(ref matrix, SKMatrix.MakeTranslation(300, 300));
transformedPath.Transform(matrix);
}
...
}
Objekt HendecagramPath má střed na (0, 0) a 11 bodů hvězdy se rozšiřuje směrem ven od tohoto středu o 100 jednotek ve všech směrech. To znamená, že cesta má kladné i záporné souřadnice. Stránka Transformace cesty dává přednost práci s hvězdičkou třikrát větší a se všemi kladnými souřadnicemi. Navíc nechce, aby jeden bod hvězdy ukazoval přímo nahoru. Místo toho chce, aby jeden bod hvězdy ukazoval přímo dolů. (Protože hvězda má 11 bodů, nemůže mít obojí.) To vyžaduje otočení hvězdy o 360 stupňů dělené 22.
Konstruktor vytvoří SKMatrix objekt ze tří samostatných transformací pomocí PostConcat metody s následujícím vzorem, kde A, B a C jsou instance SKMatrix:
SKMatrix matrix = A;
SKMatrix.PostConcat(ref A, B);
SKMatrix.PostConcat(ref A, C);
Jedná se o řadu po sobě jdoucích násobení, takže výsledek je následující:
A × B × C
Po sobě jdoucí násobení pomáhají pochopit, co každá transformace dělá. Transformace měřítka zvětšuje velikost souřadnic cesty faktorem 3, takže souřadnice jsou v rozsahu od –300 do 300. Transformace otočení otočí hvězdu kolem jejího původu. Transformace překladu ji pak posune o 300 pixelů doprava a dolů, takže všechny souřadnice se změní na pozitivní.
Existují další sekvence, které vytvářejí stejnou matici. Tady je další:
SKMatrix matrix = SKMatrix.MakeRotationDegrees(360f / 22);
SKMatrix.PostConcat(ref matrix, SKMatrix.MakeTranslation(100, 100));
SKMatrix.PostConcat(ref matrix, SKMatrix.MakeScale(3, 3));
Tím se cesta otočí kolem středu a pak ji přeloží o 100 pixelů doprava a dolů, aby všechny souřadnice byly kladné. Hvězdička se pak zvětší vzhledem k novému levému hornímu rohu, což je bod (0, 0).
Obslužná rutina PaintSurface může jednoduše vykreslit tuto cestu:
public class PathTransformPage : ContentPage
{
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint paint = new SKPaint())
{
paint.Style = SKPaintStyle.Stroke;
paint.Color = SKColors.Magenta;
paint.StrokeWidth = 5;
canvas.DrawPath(transformedPath, paint);
}
}
}
Zobrazí se v levém horním rohu plátna:
Konstruktor tohoto programu použije matici na cestu s následujícím voláním:
transformedPath.Transform(matrix);
Cesta nezachovává tuto matici jako vlastnost. Místo toho použije transformaci na všechny souřadnice cesty. Pokud Transform je znovu volána, transformace se znovu použije a jediným způsobem, jak se vrátit zpět, je použití další matice, která vrátí transformaci zpět. SKMatrix Naštěstí struktura definuje metoduTryInvert, která získá matici, která obrátí danou matici:
SKMatrix inverse;
bool success = matrix.TryInverse(out inverse);
Metoda je volána TryInverse , protože ne všechny matice jsou invertovatelné, ale nevertibilní matice není pravděpodobně použita pro grafickou transformaci.
Maticovou transformaci můžete použít také na SKPoint hodnotu, matici bodů, nebo SKRectdokonce jen jedno číslo v rámci programu. Struktura SKMatrix podporuje tyto operace s kolekcí metod, které začínají slovem Map, například:
SKPoint transformedPoint = matrix.MapPoint(point);
SKPoint transformedPoint = matrix.MapPoint(x, y);
SKPoint[] transformedPoints = matrix.MapPoints(pointArray);
float transformedValue = matrix.MapRadius(floatValue);
SKRect transformedRect = matrix.MapRect(rect);
Pokud použijete tuto poslední metodu, mějte na paměti, že SKRect struktura nedokáže reprezentovat otočený obdélník. Metoda dává smysl pouze pro SKMatrix hodnotu představující překlad a škálování.
Interaktivní experimentování
Jedním ze způsobů, jak získat pocit pro afinovou transformaci, je interaktivní přesouvání tří rohů rastrového obrázku po obrazovce a zobrazení výsledků transformace. Jedná se o myšlenku na stránce Zobrazit affine Matrix . Tato stránka vyžaduje dvě další třídy, které se používají také v jiných ukázkách:
Třída TouchPoint zobrazí průsvitný kruh, který lze přetáhnout po obrazovce. TouchPointvyžaduje, aby SKCanvasView připojený prvek nebo prvek, který je nadřazený objektem TouchEffectSKCanvasView. Nastavte vlastnost Capture na true. V obslužné rutině TouchAction události musí program volat metodu ProcessTouchEventTouchPoint pro každou TouchPoint instanci. Metoda vrátí true , pokud událost dotyku způsobila pohybující se bod dotyku. Obslužná rutina PaintSurface také musí volat metodu Paint v každé TouchPoint instanci a předat jí SKCanvas objekt.
TouchPoint demonstruje běžný způsob zapouzdření vizuálu SkiaSharp v samostatné třídě. Třída může definovat vlastnosti pro určení charakteristik vizuálu a metoda pojmenovaná Paint argumentem SKCanvas ji může vykreslit.
Vlastnost CenterTouchPoint označuje umístění objektu. Tuto vlastnost lze nastavit tak, aby inicializovala umístění; vlastnost se změní, když uživatel přetáhne kruh kolem plátna.
Stránka Zobrazit matici Affine také vyžaduje MatrixDisplay třídu. Tato třída zobrazí buňky objektu SKMatrix . Má dvě veřejné metody: Measure získání dimenzí vykreslené matice a Paint zobrazení. Třída obsahuje MatrixPaint vlastnost typu SKPaint , kterou lze nahradit jinou velikostí nebo barvou písma.
Soubor ShowAffineMatrixPage.xaml vytvoří SKCanvasView instanci a připojí .TouchEffect Soubor ShowAffineMatrixPage.xaml.cs kódem vytvoří tři TouchPoint objekty a pak je nastaví na pozice odpovídající třem rohům rastrového obrázku, který načte z vloženého prostředku:
public partial class ShowAffineMatrixPage : ContentPage
{
SKMatrix matrix;
SKBitmap bitmap;
SKSize bitmapSize;
TouchPoint[] touchPoints = new TouchPoint[3];
MatrixDisplay matrixDisplay = new MatrixDisplay();
public ShowAffineMatrixPage()
{
InitializeComponent();
string resourceID = "SkiaSharpFormsDemos.Media.SeatedMonkey.jpg";
Assembly assembly = GetType().GetTypeInfo().Assembly;
using (Stream stream = assembly.GetManifestResourceStream(resourceID))
{
bitmap = SKBitmap.Decode(stream);
}
touchPoints[0] = new TouchPoint(100, 100); // upper-left corner
touchPoints[1] = new TouchPoint(bitmap.Width + 100, 100); // upper-right corner
touchPoints[2] = new TouchPoint(100, bitmap.Height + 100); // lower-left corner
bitmapSize = new SKSize(bitmap.Width, bitmap.Height);
matrix = ComputeMatrix(bitmapSize, touchPoints[0].Center,
touchPoints[1].Center,
touchPoints[2].Center);
}
...
}
Affinová matice je jedinečně definována třemi body. Tři TouchPoint objekty odpovídají levému hornímu, pravému hornímu a levému dolnímu rohu rastrového obrázku. Vzhledem k tomu, že affinová matice je schopná transformovat obdélník pouze na paralelogram, čtvrtý bod je odvozen jinými třemi body. Konstruktor končí voláním ComputeMatrix, který vypočítá buňky objektu SKMatrix z těchto tří bodů.
Obslužná rutina TouchAction volá metodu ProcessTouchEvent každého TouchPoint. Hodnota scale se převede ze Xamarin.Forms souřadnic na pixely:
public partial class ShowAffineMatrixPage : ContentPage
{
...
void OnTouchEffectAction(object sender, TouchActionEventArgs args)
{
bool touchPointMoved = false;
foreach (TouchPoint touchPoint in touchPoints)
{
float scale = canvasView.CanvasSize.Width / (float)canvasView.Width;
SKPoint point = new SKPoint(scale * (float)args.Location.X,
scale * (float)args.Location.Y);
touchPointMoved |= touchPoint.ProcessTouchEvent(args.Id, args.Type, point);
}
if (touchPointMoved)
{
matrix = ComputeMatrix(bitmapSize, touchPoints[0].Center,
touchPoints[1].Center,
touchPoints[2].Center);
canvasView.InvalidateSurface();
}
}
...
}
Pokud se nějaká TouchPoint metoda přesunula, volá metodu ComputeMatrix znovu a zneplatní povrch.
Metoda ComputeMatrix určuje matici odvozenou těmito třemi body. Matice označovaná jako A transformuje obdélník čtverce s jedním pixelem na paralelogram založený na třech bodech, zatímco transformace měřítka označovaná jako S škáluje rastrový obrázek na obdélník čtverce s jedním pixelem. Složená matice je S × A:
public partial class ShowAffineMatrixPage : ContentPage
{
...
static SKMatrix ComputeMatrix(SKSize size, SKPoint ptUL, SKPoint ptUR, SKPoint ptLL)
{
// Scale transform
SKMatrix S = SKMatrix.MakeScale(1 / size.Width, 1 / size.Height);
// Affine transform
SKMatrix A = new SKMatrix
{
ScaleX = ptUR.X - ptUL.X,
SkewY = ptUR.Y - ptUL.Y,
SkewX = ptLL.X - ptUL.X,
ScaleY = ptLL.Y - ptUL.Y,
TransX = ptUL.X,
TransY = ptUL.Y,
Persp2 = 1
};
SKMatrix result = SKMatrix.MakeIdentity();
SKMatrix.Concat(ref result, A, S);
return result;
}
...
}
PaintSurface Nakonec metoda vykreslí rastrový obrázek na základě této matice, zobrazí matici v dolní části obrazovky a vykresluje dotykové body ve třech rozích rastrového obrázku:
public partial class ShowAffineMatrixPage : ContentPage
{
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
// Display the bitmap using the matrix
canvas.Save();
canvas.SetMatrix(matrix);
canvas.DrawBitmap(bitmap, 0, 0);
canvas.Restore();
// Display the matrix in the lower-right corner
SKSize matrixSize = matrixDisplay.Measure(matrix);
matrixDisplay.Paint(canvas, matrix,
new SKPoint(info.Width - matrixSize.Width,
info.Height - matrixSize.Height));
// Display the touchpoints
foreach (TouchPoint touchPoint in touchPoints)
{
touchPoint.Paint(canvas);
}
}
}
Na následující obrazovce iOS se zobrazí rastrový obrázek při prvním načtení stránky, zatímco dvě ostatní obrazovky ji zobrazují po určité manipulaci:
I když se zdá, že dotykové body přetahuje rohy rastrového obrázku, to je jen iluze. Matice vypočítaná z dotykových bodů transformuje rastrový obrázek tak, aby se rohy shodovaly s dotykovými body.
Je přirozenější, aby uživatelé mohli přesouvat, měnit velikost a otáčet rastrové obrázky, nikoli přetažením rohů, ale přetažením, přetažením, stažením a otočením jedním nebo dvěma prsty přímo na objektu. Toto je popsáno v dalším článku Manipulace s dotykovým ovládáním.
Důvod matice 3 po 3
Je možné očekávat, že dvourozměrný grafický systém bude vyžadovat pouze transformační matici 2 po 2:
│ ScaleX SkewY │
| x y | × │ │ = | x' y' |
│ SkewX ScaleY │
To funguje pro škálování, otáčení a dokonce i skewing, ale není schopen nejzákladnější transformace, což je překlad.
Problémem je, že matice 2 by-2 představuje lineární transformaci ve dvou dimenzích. Lineární transformace zachovává některé základní aritmetické operace, ale jedním z důsledků je, že lineární transformace nikdy nezmění bod (0, 0). Lineární transformace znemožňuje překlad.
Ve třech dimenzích vypadá matice lineární transformace takto:
│ ScaleX SkewYX SkewZX │
| x y z | × │ SkewXY ScaleY SkewZY │ = | x' y' z' |
│ SkewXZ SkewYZ ScaleZ │
Buňka označená SkewXY znamená, že hodnota zkosí souřadnici X na základě hodnot Y. Buňka SkewXZ znamená, že hodnota zkosí souřadnici X na základě hodnot Z a hodnoty se pro ostatní Skew buňky zkosí podobně.
Tuto 3D transformační matici je možné omezit na dvourozměrnou rovinu nastavením SkewZX a SkewZY na 0 a ScaleZ na 1:
│ ScaleX SkewYX 0 │
| x y z | × │ SkewXY ScaleY 0 │ = | x' y' z' |
│ SkewXZ SkewYZ 1 │
Pokud se dvojrozměrná grafika nakreslí úplně na rovině v prostorech 3D, kde se Z rovná 1, násobení transformace vypadá takto:
│ ScaleX SkewYX 0 │
| x y 1 | × │ SkewXY ScaleY 0 │ = | x' y' 1 |
│ SkewXZ SkewYZ 1 │
Všechno zůstává na dvourozměrné rovině, kde se Z rovná 1, ale SkewXZ buňky se SkewYZ efektivně stávají faktory dvojrozměrného překladu.
Takto třírozměrná lineární transformace slouží jako dvojrozměrná nelineární transformace. (Analogicky jsou transformace v 3D grafikách založeny na matici 4 po 4.)
Struktura SKMatrix v SkiaSharp definuje vlastnosti pro tento třetí řádek:
│ ScaleX SkewY Persp0 │
| x y 1 | × │ SkewX ScaleY Persp1 │ = | x' y' z` |
│ TransX TransY Persp2 │
Nenulové hodnoty Persp0 a Persp1 výsledkem jsou transformace, které přesunou objekty z dvojrozměrné roviny, kde se Z rovná 1. Co se stane, když se tyto objekty přesunou zpět do této roviny, najdete v článku o transformacích mimo Affine.

