Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
2B nesneleri 3B alanda döndürmek için benfin olmayan dönüşümleri kullanın.
Afin olmayan dönüşümlerin yaygın bir uygulaması, 2B nesnenin 3B alanda döndürülmesini simüle etmektir:

Bu iş, üç boyutlu döndürmelerle çalışmayı ve ardından bu 3B döndürmeleri gerçekleştiren bir benfin SKMatrix olmayan dönüşüm türetmesini içerir.
Bu SKMatrix dönüşümü yalnızca iki boyutta çalışarak geliştirmek zordur. Bu 3'e 3 matris, 3B grafiklerde kullanılan 4'e 4 matristen türetildiğinde iş çok daha kolay hale gelir. SkiaSharp bu amaca yönelik sınıfı içerir SKMatrix44 , ancak 3B döndürmeleri ve 4'e 4 dönüşüm matrisini anlamak için 3B grafiklerde bazı arka plan gereklidir.
Üç boyutlu koordinat sistemi Z adlı üçüncü bir eksen ekler. Kavramsal olarak, Z ekseni ekrana dik açılardadır. 3B boşluktaki koordinat noktaları üç sayıyla gösterilir: (x, y, z). Bu makalede kullanılan 3B koordinat sisteminde, X değerlerinin artırılması sağdadır ve Y değerlerinin artması iki boyutta olduğu gibi aşağı gider. Pozitif Z değerlerinin artırılması ekrandan çıkar. Çıkış noktası, 2B grafiklerde olduğu gibi sol üst köşedir. Ekranı, bu düzleme doğru açılarda Z ekseni olan bir XY düzlemi olarak düşünebilirsiniz.
Buna sol koordinat sistemi denir. Sol elinizin işaretleyicisini pozitif X koordinatları yönünde (sağda) ve orta parmağınızı Y koordinatlarını artırma (aşağı) yönünde gösterirseniz, başparmak noktanız ekrandan dışarı doğru uzanan Z koordinatlarını artırma yönündedir.
3B grafiklerde dönüşümler 4'e 4 matrisi temel alır. 4'e 4 kimlik matrisi aşağıdadır:
| 1 0 0 0 | | 0 1 0 0 | | 0 0 1 0 | | 0 0 0 1 |
4'e 4 matrisle çalışırken, hücreleri satır ve sütun numaralarıyla tanımlamak uygundur:
| M11 M12 M13 M14 | | M21 M22 M23 M24 | | M31 M32 M33 M34 | | M41 M42 M43 M44 |
Ancak SkiaSharp Matrix44 sınıfı biraz farklıdır. içindeki tek tek hücre değerlerini SKMatrix44 ayarlamanın veya almanın tek yolu dizin oluşturucuyu Item kullanmaktır. Satır ve sütun dizinleri tek tabanlı değil sıfır tabanlıdır ve satırlar ve sütunlar değiştirilir. Yukarıdaki diyagramdaki M14 hücresine bir SKMatrix44 nesnedeki dizin oluşturucu [3, 0] kullanılarak erişilir.
3B grafik sisteminde 3B nokta (x, y, z) 4'e 4 dönüştürme matrisi ile çarpmak için 1'e 4 matrise dönüştürülür:
| M11 M12 M13 M14 |
| x y z 1 | × | M21 M22 M23 M24 | = | x' y' z' w' |
| M31 M32 M33 M34 |
| M41 M42 M43 M44 |
Üç boyutta gerçekleşen 2B dönüşümlere benzer şekilde, 3B dönüşümlerin dört boyutta gerçekleştiği varsayılır. Dördüncü boyut W olarak adlandırılır ve 3B alanın W koordinatlarının 1'e eşit olduğu 4B boşluk içinde mevcut olduğu varsayılır. Dönüşüm formülleri aşağıdaki gibidir:
x' = M11·x + M21·y + M31·z + M41
y' = M12·x + M22·y + M32·z + M42
z' = M13·x + M23·y + M33·z + M43
w' = M14·x + M24·y + M34·z + M44
Dönüştürme formüllerinde, , M22M33 hücrelerinin M11X, Y ve Z yönlerinde ölçeklendirme faktörleri olduğu ve XM42M43, Y ve Z yönlerinde M41çeviri faktörleri olduğu açıktır.
Bu koordinatları W'nin 1'e eşit olduğu 3B alana geri dönüştürmek için x', y' ve z' koordinatlarının tümü w':
x" = x' / w'
y" = y' / w'
z" = z' / w'
w" = w' / w' = 1
w' ile bölme, 3B alanda perspektif sağlar. w' değeri 1'e eşitse perspektif oluşmaz.
3B alanda döndürmeler oldukça karmaşık olabilir, ancak en basit döndürmeler X, Y ve Z eksenlerinin etrafındaki döndürmelerdir. X ekseni etrafında açılı α döndürme şu matristir:
| 1 0 0 0 | | 0 cos(α) sin(α) 0 | | 0 –sin(α) cos(α) 0 | | 0 0 0 1 |
X değerleri bu dönüşüme tabi tutulduğunda aynı kalır. Y ekseni etrafında döndürme, Y değerlerini değişmeden bırakır:
| cos(α) 0 –sin(α) 0 | | 0 1 0 0 | | sin(α) 0 cos(α) 0 | | 0 0 0 1 |
Z ekseni etrafında döndürme, 2B grafiklerle aynıdır:
| cos(α) sin(α) 0 0 | | –sin(α) cos(α) 0 0 | | 0 0 1 0 | | 0 0 0 1 |
Döndürme yönü koordinat sisteminin teslimi ile örtülür. Bu sol elle kullanılan bir sistemdir, dolayısıyla sol elinizin başparmağını belirli bir eksen için artan değerlere yönlendirirseniz ( X ekseni etrafında döndürme için sağda, Y ekseni etrafında döndürme için aşağı ve Z ekseni etrafında döndürme için size doğru) diğer parmaklarınızın eğrisi pozitif açıların döndürme yönünü gösterir.
SKMatrix44 , döndürmenin gerçekleştiği ekseni belirtmenize olanak tanıyan statik CreateRotation ve CreateRotationDegrees yöntemleri genelleştirdi:
public static SKMatrix44 CreateRotationDegrees (Single x, Single y, Single z, Single degrees)
X ekseni etrafında döndürmek için ilk üç bağımsız değişkeni 1, 0, 0 olarak ayarlayın. Y ekseni etrafında döndürmek için, bunları 0, 1, 0 olarak ayarlayın ve Z ekseni etrafında döndürmek için bunları 0, 0, 1 olarak ayarlayın.
4'e 4'ün dördüncü sütunu perspektif içindir. , SKMatrix44 perspektif dönüşümleri oluşturmak için hiçbir yönteme sahip değildir, ancak aşağıdaki kodu kullanarak kendiniz oluşturabilirsiniz:
SKMatrix44 perspectiveMatrix = SKMatrix44.CreateIdentity();
perspectiveMatrix[3, 2] = -1 / depth;
Bağımsız değişken adının depth nedeni kısa süre sonra açıklanacaktır. Bu kod matrisi oluşturur:
| 1 0 0 0 | | 0 1 0 0 | | 0 0 1 -1/depth | | 0 0 0 1 |
Dönüştürme formülleri aşağıdaki w' hesaplamasının sonucunu verir:
w' = –z / depth + 1
Bu, Z değerleri sıfırdan küçük olduğunda (kavramsal olarak XY düzleminin arkasında) X ve Y koordinatlarını azaltmaya ve pozitif Z değerleri için X ve Y koordinatlarını artırmaya hizmet eder. Z koordinatı eşit deptholduğunda, w' sıfır olur ve koordinatlar sonsuz olur. Üç boyutlu grafik sistemleri bir kamera metaforu etrafında oluşturulur ve depth buradaki değer kameranın koordinat sisteminin kaynağından uzaklığı temsil eder. Grafik bir nesnenin kaynağından birim olarak gelen bir Z koordinatı depth varsa, kavramsal olarak kameranın merceğine dokunuyor ve sonsuz büyük hale geliyor.
Bu perspectiveMatrix değeri büyük olasılıkla döndürme matrisleriyle birlikte kullanacağınızı unutmayın. Döndürülmekte olan grafik nesnesinin X veya Y koordinatları değerinden depthbüyükse, bu nesnenin 3B alanda döndürülmesinin büyük olasılıkla değerinden depthbüyük Z koordinatları içermesi gerekir. Bundan kaçınılmalıdır! Oluştururken perspectiveMatrix , nasıl döndürülürse döndürülsün grafik nesnesindeki tüm koordinatlar için yeterince büyük bir değere ayarlamak depth istiyorsunuz. Bu, hiçbir zaman sıfıra bölme olmamasını sağlar.
3B döndürmeleri ve perspektifi birleştirmek için 4'e 4 matrislerin birlikte çarpılması gerekir. Bu amaçla birleştirme SKMatrix44 yöntemlerini tanımlar. ve B nesneleriyse SKMatrix44A, aşağıdaki kod A'yı A × B'ye eşit olarak ayarlar:
A.PostConcat(B);
2B grafik sisteminde 4'e 4 dönüştürme matrisi kullanıldığında, 2B nesnelere uygulanır. Bu nesneler düz ve Z koordinatlarının sıfır olduğu varsayılır. Dönüşüm çarpması, daha önce gösterilen dönüşümden biraz daha basittir:
| M11 M12 M13 M14 |
| x y 0 1 | × | M21 M22 M23 M24 | = | x' y' z' w' |
| M31 M32 M33 M34 |
| M41 M42 M43 M44 |
z için bu 0 değeri, matrisin üçüncü satırında hiçbir hücre içermeyen dönüştürme formülleriyle sonuç verir:
x' = M11·x + M21·y + M41
y' = M12·x + M22·y + M42
z' = M13·x + M23·y + M43
w' = M14·x + M24·y + M44
Ayrıca, z' koordinatı da burada ilgisizdir. 2B grafik sisteminde bir 3B nesne görüntülendiğinde, Z koordinat değerleri yoksayılarak iki boyutlu bir nesneye daraltılır. Dönüşüm formülleri yalnızca şu iki formülden ibarettir:
x" = x' / w'
y" = y' / w'
Başka bir deyişle, 4'e 4 matrisin üçüncü satırı ve üçüncü sütunu yoksayılabilir.
Ama böyleyse, neden 4'e 4 matris en başta gerekli?
4'e 4'ün üçüncü satırı ve üçüncü sütunu iki boyutlu dönüşümler için ilgisiz olsa da, çeşitli SKMatrix44 değerler birlikte çarpıldığında üçüncü satır ve sütun bundan önce bir rol oynar. Örneğin, Y ekseni çevresinde döndürmeyi perspektif dönüşümüyle çarpıttığını varsayalım:
| cos(α) 0 –sin(α) 0 | | 1 0 0 0 | | cos(α) 0 –sin(α) sin(α)/depth | | 0 1 0 0 | × | 0 1 0 0 | = | 0 1 0 0 | | sin(α) 0 cos(α) 0 | | 0 0 1 -1/depth | | sin(α) 0 cos(α) -cos(α)/depth | | 0 0 0 1 | | 0 0 0 1 | | 0 0 0 1 |
Üründe, hücre M14 artık bir perspektif değeri içeriyor. Bu matrisi 2B nesnelere uygulamak istiyorsanız üçüncü satır ve sütun ortadan kaldırılarak 3'e 3 matrise dönüştürülür:
| cos(α) 0 sin(α)/depth | | 0 1 0 | | 0 0 1 |
Artık bir 2B noktayı dönüştürmek için kullanılabilir:
| cos(α) 0 sin(α)/depth |
| x y 1 | × | 0 1 0 | = | x' y' z' |
| 0 0 1 |
Dönüşüm formülleri şunlardır:
x' = cos(α)·x
y' = y
z' = (sin(α)/depth)·x + 1
Şimdi her şeyi z'ye bölün:
x" = cos(α)·x / ((sin(α)/depth)·x + 1)
y" = y / ((sin(α)/depth)·x + 1)
2B nesneler Y ekseni etrafında pozitif bir açıyla döndürüldüğünde pozitif X değerleri arka plana dönerken negatif X değerleri ön plana gelir. Y ekseninden en uzak koordinatlar görüntüleyiciden uzaklaştıkça veya görüntüleyiciye yaklaştıkça daha küçük veya daha büyük hale geldiğinden X değerleri Y eksenine daha yakın (kosinüs değeri tarafından yönetilir) yakınlaşır.
kullanırken SKMatrix44, çeşitli SKMatrix44 değerleri çarparak tüm 3B döndürme ve perspektif işlemlerini gerçekleştirin. Ardından, sınıfın özelliğini SKMatrix44 kullanarak Matrix 4'e 4 matristen iki boyutlu 3'e 3 matris ayıklayabilirsiniz. Bu özellik tanıdık SKMatrix bir değer döndürür.
Döndürme 3B sayfası, 3B döndürme ile deneme yapmanızı sağlar. Rotation3DPage.xaml dosyası X, Y ve Z eksenleri çevresinde döndürmeyi ayarlamak ve derinlik değeri ayarlamak için dört kaydırıcı örneği oluşturur:
<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.Transforms.Rotation3DPage"
Title="Rotation 3D">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
<Style TargetType="Slider">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="Maximum" Value="360" />
</Style>
</ResourceDictionary>
</Grid.Resources>
<Slider x:Name="xRotateSlider"
Grid.Row="0"
ValueChanged="OnSliderValueChanged" />
<Label Text="{Binding Source={x:Reference xRotateSlider},
Path=Value,
StringFormat='X-Axis Rotation = {0:F0}'}"
Grid.Row="1" />
<Slider x:Name="yRotateSlider"
Grid.Row="2"
ValueChanged="OnSliderValueChanged" />
<Label Text="{Binding Source={x:Reference yRotateSlider},
Path=Value,
StringFormat='Y-Axis Rotation = {0:F0}'}"
Grid.Row="3" />
<Slider x:Name="zRotateSlider"
Grid.Row="4"
ValueChanged="OnSliderValueChanged" />
<Label Text="{Binding Source={x:Reference zRotateSlider},
Path=Value,
StringFormat='Z-Axis Rotation = {0:F0}'}"
Grid.Row="5" />
<Slider x:Name="depthSlider"
Grid.Row="6"
Maximum="2500"
Minimum="250"
ValueChanged="OnSliderValueChanged" />
<Label Grid.Row="7"
Text="{Binding Source={x:Reference depthSlider},
Path=Value,
StringFormat='Depth = {0:F0}'}" />
<skia:SKCanvasView x:Name="canvasView"
Grid.Row="8"
PaintSurface="OnCanvasViewPaintSurface" />
</Grid>
</ContentPage>
değerinin depthSlider 250 değeriyle Minimum başlatıldığına dikkat edin. Bu, burada döndürülen 2B nesnenin X ve Y koordinatlarının, kaynağın etrafındaki 250 piksel yarıçapı tarafından tanımlanan bir daireyle kısıtlandığını gösterir. Bu nesnenin 3B alanda herhangi bir döndürmesi her zaman 250'den küçük koordinat değerleriyle sonuçlanır.
Rotation3DPage.cs arka planda kod dosyası 300 piksel kare olan bir bit eşlem içinde yüklenir:
public partial class Rotation3DPage : ContentPage
{
SKBitmap bitmap;
public Rotation3DPage()
{
InitializeComponent();
string resourceID = "SkiaSharpFormsDemos.Media.SeatedMonkey.jpg";
Assembly assembly = GetType().GetTypeInfo().Assembly;
using (Stream stream = assembly.GetManifestResourceStream(resourceID))
{
bitmap = SKBitmap.Decode(stream);
}
}
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
if (canvasView != null)
{
canvasView.InvalidateSurface();
}
}
...
}
3B dönüşüm bu bit eşlem üzerinde ortalanmışsa, X ve Y koordinatları –150 ile 150 arasında değişirken köşeler merkezden 212 pikseldir, dolayısıyla her şey 250 piksel yarıçap içinde olur.
İşleyici, PaintSurface kaydırıcıları temel alan nesneler oluşturur SKMatrix44 ve kullanarak PostConcatbunları birlikte çarpar. SKMatrix Son SKMatrix44 nesneden ayıklanan değer, döndürmeyi ekranın ortasında ortalamak için çeviri dönüşümleriyle çevrilir:
public partial class Rotation3DPage : ContentPage
{
SKBitmap bitmap;
public Rotation3DPage()
{
InitializeComponent();
string resourceID = "SkiaSharpFormsDemos.Media.SeatedMonkey.jpg";
Assembly assembly = GetType().GetTypeInfo().Assembly;
using (Stream stream = assembly.GetManifestResourceStream(resourceID))
{
bitmap = SKBitmap.Decode(stream);
}
}
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
if (canvasView != null)
{
canvasView.InvalidateSurface();
}
}
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);
// Use 3D matrix for 3D rotations and perspective
SKMatrix44 matrix44 = SKMatrix44.CreateIdentity();
matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(1, 0, 0, (float)xRotateSlider.Value));
matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(0, 1, 0, (float)yRotateSlider.Value));
matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(0, 0, 1, (float)zRotateSlider.Value));
SKMatrix44 perspectiveMatrix = SKMatrix44.CreateIdentity();
perspectiveMatrix[3, 2] = -1 / (float)depthSlider.Value;
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 bitmap
canvas.SetMatrix(matrix);
float xBitmap = xCenter - bitmap.Width / 2;
float yBitmap = yCenter - bitmap.Height / 2;
canvas.DrawBitmap(bitmap, xBitmap, yBitmap);
}
}
Dördüncü kaydırıcıyı denediğinizde, farklı derinlik ayarlarının nesneyi görüntüleyiciden daha uzağa taşımadığını, bunun yerine perspektif efektinin kapsamını değiştirdiğini fark edeceksiniz:
Animasyonlu Döndürme 3B , 3B boşlukta bir metin dizesine animasyon eklemek için de kullanır SKMatrix44 . Alan textPaint olarak ayarlanan nesne, metnin sınırlarını belirlemek için oluşturucuda kullanılır:
public class AnimatedRotation3DPage : ContentPage
{
SKCanvasView canvasView;
float xRotationDegrees, yRotationDegrees, zRotationDegrees;
string text = "SkiaSharp";
SKPaint textPaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Black,
TextSize = 100,
StrokeWidth = 3,
};
SKRect textBounds;
public AnimatedRotation3DPage()
{
Title = "Animated Rotation 3D";
canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
// Measure the text
textPaint.MeasureText(text, ref textBounds);
}
...
}
Geçersiz OnAppearing kılma, , yRotationDegreesve zRotationDegrees alanlarına farklı oranlarda animasyon xRotationDegreeseklemek için üç Xamarin.FormsAnimation nesne tanımlar. Bu animasyonların dönemlerinin asal sayılara (5 saniye, 7 saniye ve 11 saniye) ayarlandığına dikkat edin; bu nedenle genel birleşim yalnızca 385 saniyede bir veya 10 dakikadan fazla tekrar eder:
public class AnimatedRotation3DPage : ContentPage
{
...
protected override void OnAppearing()
{
base.OnAppearing();
new Animation((value) => xRotationDegrees = 360 * (float)value).
Commit(this, "xRotationAnimation", length: 5000, repeat: () => true);
new Animation((value) => yRotationDegrees = 360 * (float)value).
Commit(this, "yRotationAnimation", length: 7000, repeat: () => true);
new Animation((value) =>
{
zRotationDegrees = 360 * (float)value;
canvasView.InvalidateSurface();
}).Commit(this, "zRotationAnimation", length: 11000, repeat: () => true);
}
protected override void OnDisappearing()
{
base.OnDisappearing();
this.AbortAnimation("xRotationAnimation");
this.AbortAnimation("yRotationAnimation");
this.AbortAnimation("zRotationAnimation");
}
...
}
Önceki programda olduğu gibi işleyici döndürme PaintCanvas ve perspektif için değerler oluşturur SKMatrix44 ve bunları birlikte çarpar:
public class AnimatedRotation3DPage : ContentPage
{
...
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);
// Scale so text fits
float scale = Math.Min(info.Width / textBounds.Width,
info.Height / textBounds.Height);
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;
canvas.DrawText(text, xText, yText, textPaint);
}
}
Bu 3B döndürme, döndürme merkezini ekranın ortasına taşımak ve metin dizesinin boyutunu ekranla aynı genişlikte olacak şekilde ölçeklendirmek için birkaç 2B dönüşümle çevrelenmiştir:

