目前博客園中成系列的Direct2D的教程有html
一、萬一的 Direct2D 系列,用的是Delphi 2009windows
二、zdd的 Direct2D 系列,用的是VS中的C++函數
三、本文所在的 Direct2D教程 系列,用的是VS2010的Visual Basic語言(能夠很方便的轉爲C#),基於Windows API Code Pack 1.1。spa
還有官方的說明文檔 Direct2D ,用的是C++。.net
本系列的前幾篇文章:3d
Direct2D教程I——簡介及首個例子orm
Direct2D教程II——繪製基本圖形和線型(StrokeStyle)的設置詳解htm
Direct2D教程III——幾何(Geometry)對象對象
Direct2D教程IV——筆刷(Brush)對象blog
Direct2D教程V——位圖(Bitmap)和位圖筆刷(BitmapBrush)
自GDI+開始,GDI+、WPF、Direct2D一路過來,轉換(Transform)始終是一個重要的內容,經過轉換(Transform)能實現一些特殊的效果。
轉換(Transform):經過必定的運算,把一個平面座標系的點變換爲另外一個座標系的點。
目前變換主要有平移轉換(TranslateTransform)、旋轉轉換(RotateTransform)、縮放轉換(ScaleTransform)、傾斜轉換(SkewTransform)
因爲圖形是由點組成的,所以轉換也能把圖形轉換成另外一個圖形
轉換(Transform)的矩陣知識
在.net中(包括GDI+、WPF、Direct2D),轉換(Transform)是經過定義轉換矩陣實現的。源點P(X,Y),經過轉換(Transform)後獲得目標點P1(X1,Y1),是經過轉換矩陣M來實現的。把點的座標擴成3個份量,前2個份量分別是X份量和Y份量,最後1個份量定義成1。則源點P(X,Y,1),目標點P1(X1,Y1,1)。
轉換矩陣M是個3*3的矩陣,最後1列的3個數字自上而下分別是0、0、1。則M矩陣以下所示
![image image](http://static.javashuo.com/static/loading.gif)
M矩陣中起到決定做用是第一、2列的6個數字
則轉換的基本計算公式是
P1=P×M
X1=X*m11+Y*m21+m31
Y1=X*m12+Y*m22+m32
平移轉換(TranslateTransform)
以下圖所示,平移轉換(TranslateTransform),把T1轉換到T2。
![image image](http://static.javashuo.com/static/loading.gif)
很容易的推導出,x2=x1+dx,y2=y1+dy。由上面的基本計算公式,能夠推導出轉換矩陣M
![image image](http://static.javashuo.com/static/loading.gif)
![image image](http://static.javashuo.com/static/loading.gif)
旋轉轉換(RotateTransform)
旋轉轉換(RotateTransform)以下圖所示,T1繞着原點旋轉Θ,轉換到T2點
![image image](http://static.javashuo.com/static/loading.gif)
假設OT1的距離是R,T1和X軸的夾角是α。則x1和y1的公式爲
x1=R·Cosα
y1=R·Sinα
同理的,x2和y2的公式爲
x2=R·Cos(α+Θ)=R·Cosα·CosΘ-R·Sinα·SinΘ=x1·CosΘ-y1·SinΘ
y2=R·Sin(α+Θ)=R·Sinα·CosΘ+R·Cosα·SinΘ=y1·CosΘ+x1·SinΘ
由上面的基本計算公式,能夠推導出轉換矩陣M
![image image](http://static.javashuo.com/static/loading.gif)
![image image](http://static.javashuo.com/static/loading.gif)
縮放轉換(ScaleTransform)
縮放轉換(ScaleTransform)以下圖所示,T1沿着X軸縮放dx倍、Y軸縮放dy倍,轉換到T2點
![image image](http://static.javashuo.com/static/loading.gif)
很容易的推導出,x2=x1·dx,y2=y1·dy。由上面的基本計算公式,能夠推導出轉換矩陣M
![image image](http://static.javashuo.com/static/loading.gif)
![image image](http://static.javashuo.com/static/loading.gif)
傾斜轉換(SkewTransform)
傾斜轉換(SkewTransform)以下圖所示,Y軸向右旋轉Θ1到Y',X軸向下旋轉Θ2到X',T1轉換到T2點
![image image](http://static.javashuo.com/static/loading.gif)
在上圖中的紅色輔助線的幫助下,能夠推導出,x2=x1+y1·TanΘ1,y2=y1+x1·TanΘ2。由上面的基本計算公式,能夠推導出轉換矩陣M
![image image](http://static.javashuo.com/static/loading.gif)
![image image](http://static.javashuo.com/static/loading.gif)
在咱們常見的四種轉換(平移轉換(TranslateTransform)、旋轉轉換(RotateTransform)、縮放轉換(ScaleTransform)、傾斜轉換(SkewTransform))均可以用轉換矩陣M來表達。
但轉換矩陣的優點不只僅是四種轉化。他還能夠衍生出其餘的轉化
複合轉換
上面介紹的四種轉化都是轉化基準點在原點。若是如今我有需求,繞着(2,1)這個點旋轉30度的這個轉換怎麼辦?
實際上,能夠把這個轉換分解成三個轉換
一、先是平移轉換,把(2,1)平移到(0,0)
二、再是旋轉轉換,繞着原點旋轉30度
三、再是平移轉換,把(0,0)平移到(2,1)
則這個轉換矩陣M能夠用三個轉換的轉換矩陣的連乘來表示
![image image](http://static.javashuo.com/static/loading.gif)
![image image](http://static.javashuo.com/static/loading.gif)
要注意的是矩陣的運算不知足交換率,即M1·M2和M2·M1不必定相等
Direct2D中的轉換矩陣
在Direct2D中,也是用矩陣來表示轉換。轉換矩陣的結構是Matrix3x2F
在上面的說明中,矩陣的最後1列是固定的三個數字(0,0,1)。所以結構Matrix3x2F在內部的實現是經過6個變量來實現的(m十一、m十二、m2一、m2二、m3一、m32)。
來看看結構Matrix3x2F的原型定義
Direct2D1.
Matrix3x2F(m11
As
Single, m12
As
Single, m21
As
Single, m22
As
Single, m31
As
Single, m32
As
Single)
Public
Shared
ReadOnly
Property Identity()
As Direct2D1.
Matrix3x2F
Public
Shared
Function Translation(x
As
Single, y
As
Single)
As Direct2D1.
Matrix3x2F
Public
Shared
Function Translation(size
As Direct2D1.
SizeF)
As Direct2D1.
Matrix3x2F
Public
Shared
Function Scale(x
As
Single, y
As
Single)
As Direct2D1.
Matrix3x2F
Public
Shared
Function Scale(x
As
Single, y
As
Single, center
As Direct2D1.
Point2F)
As Direct2D1.
Matrix3x2F
Public
Shared
Function Scale(size
As Direct2D1.
SizeF)
As Direct2D1.
Matrix3x2F
Public
Shared
Function Scale(size
As Direct2D1.
SizeF, center
As Direct2D1.
Point2F)
As Direct2D1.
Matrix3x2F
Public
Shared
Function Rotation(angle
As
Single)
As Direct2D1.
Matrix3x2F
Public
Shared
Function Rotation(angle
As
Single, center
As Direct2D1.
Point2F)
As Direct2D1.
Matrix3x2F
Public
Shared
Function Skew(angleX
As
Single, angleY
As
Single)
As Direct2D1.
Matrix3x2F
Public
Shared
Function Skew(angleX
As
Single, angleY
As
Single, center
As Direct2D1.
Point2F)
As Direct2D1.
Matrix3x2F
從上面的原型定義能夠看出,結構Matrix3x2F以共享方法的形式提供了四種基本的轉換。在旋轉轉換(RotateTransform)、縮放轉換(ScaleTransform)、傾斜轉換(SkewTransform)的共享方法中還提供了以不一樣基準點的轉換的方法。這樣,就免去了本身再額外計算的過程。
不過因爲沒有提供矩陣乘法的函數,也就是在其餘的複合轉換中,只能本身進行計算。這也是這個結構的侷限性。(或者微軟認爲,只須要這幾個轉換就足夠了。實際上在Direct2D的基本類庫中是提供了矩陣的乘法。在封裝成Windows API Code Pack 1.1後,反而是取消了矩陣乘法)
GDI+、WPF中的轉換矩陣
除了Direct2D中的結構Matrix3x2F外。在System.Drawing.Drawing2D空間下也提供告終構Matrix,用於GDI+和WPF中的轉換矩陣。這個結構提供了三個很是有用的方法
Public
Sub Multiply(matrix
As Drawing2D.
Matrix)
Public
ReadOnly
Property IsInvertible()
As
Boolean
Public
Sub Invert()
第一個方法將指定的矩陣和自身相乘(自身在後,能夠用這個函數的另外一個重載來實現矩陣的位置不一樣),提供了矩陣的乘法,實現了自定義的複合轉換
第二個屬性是判斷該矩陣是否可逆
第三個方法是對該矩陣求逆矩陣。求逆矩陣的意義在於得到逆轉換。(我以爲這個方法很實用,惋惜在Direct2D中沒有提供這個方法)
利用結構Matrix實現Direct2D中的Matrix3x2F的矩陣乘法和逆矩陣
咱們能夠利用結構Matrix來在Direct2D中實現矩陣乘法和逆矩陣,代碼以下:
Public
Function Multiply(M1
As Direct2D1.
Matrix3x2F, M2
As Direct2D1.
Matrix3x2F)
As Direct2D1.
Matrix3x2F
Dim S1
As
New Drawing2D.
Matrix(M1.M11, M1.M12, M1.M21, M1.M22, M1.M31, M1.M32)
Dim S2
As
New Drawing2D.
Matrix(M2.M11, M2.M12, M2.M21, M2.M22, M2.M31, M2.M32)
S1.Multiply(S2, Drawing2D.
MatrixOrder.Append)
Dim S()
As
Single = S1.Elements
Return
New Direct2D1.
Matrix3x2F(S(0), S(1), S(2), S(3), S(4), S(5))
End
Function
Public
Function Invert(M1
As Direct2D1.
Matrix3x2F)
As Direct2D1.
Matrix3x2F
Dim S1
As
New Drawing2D.
Matrix(M1.M11, M1.M12, M1.M21, M1.M22, M1.M31, M1.M32)
If S1.IsInvertible =
True
Then S1.Invert()
Dim S()
As
Single = S1.Elements
Return
New Direct2D1.
Matrix3x2F(S(0), S(1), S(2), S(3), S(4), S(5))
End
Function
自定義的仿射轉換(AffineTransform)
仿射轉換(AffineTransform)和傾斜轉換(SkewTransform)相似,都是經過旋轉座標軸來轉換,具體的區別看下面的示意圖
![image image](http://static.javashuo.com/static/loading.gif)
區別在於仿射轉換(AffineTransform)在旋轉座標軸的時候,座標軸上的單位長度沒有發生變化(傾斜轉換(SkewTransform)座標軸的單位長度是發生變化的)。
我的以爲,仿射轉換(AffineTransform)比傾斜轉換(SkewTransform)更加接近於真實的視覺轉換
能夠推導出,x2=x1·CosΘ2+y1·SinΘ1,y2=x1·SinΘ2+y1·CosΘ1。由上面的基本計算公式,能夠推導出轉換矩陣M
![image image](http://static.javashuo.com/static/loading.gif)
![image image](http://static.javashuo.com/static/loading.gif)
因爲在Direct2D中沒有提供仿射轉換(AffineTransform)的函數,所以本身編寫一個仿射轉換(AffineTransform)的矩陣函數。代碼以下:
Public
Function AffineMatrix(angelX
As
Single, angelY
As
Single)
As Direct2D1.
Matrix3x2F
Dim M
As
New Direct2D1.
Matrix3x2F
M.M11 =
Math.Cos(angelY *
Math.PI / 180)
M.M12 =
Math.Sin(angelY *
Math.PI / 180)
M.M21 =
Math.Sin(angelX *
Math.PI / 180)
M.M22 =
Math.Cos(angelX *
Math.PI / 180)
M.M31 = 0
M.M32 = 0
Return M
End
Function
轉換(Transform)在Direct2D中運用的範圍
在Direct2D中,什麼對象能運用轉換(Transform)?答案是不少,能夠是畫布(RenderTarget對象,至關於改變畫布的座標系)、筆刷(Brush對象,主要是用於位圖筆刷(BitmapBrush),更改位圖筆刷(BitmapBrush)的起始位置等)、形狀(更改形狀的外形、位置等)。幾乎全部的對象都能運用轉換
下面這個例子,是在畫布(RenderTarget)上運用轉換的例子。先看看準備的文件
![218 218](http://static.javashuo.com/static/loading.gif)
這個是以前的216.png,如今加上一圈紅邊後,保存爲218.png。
Public
Class
clsDirect2DSample14
Inherits
clsDirect2DSample11
Public
Shadows
Sub Render()
If
Not _renderTarget
Is
Nothing
Then
With _renderTarget
.BeginDraw()
.Clear(
New Direct2D1.
ColorF(
Color.Chocolate.ToArgb))
Dim B
As Direct2D1.
D2DBitmap = LoadBitmapFromFile(
"218.png")
Dim BB
As Direct2D1.
BitmapBrush = _renderTarget.CreateBitmapBrush(B)
BB.Transform = Direct2D1.
Matrix3x2F.Scale(0.25, 0.25)
BB.ExtendModeX = Direct2D1.
ExtendMode.Wrap
BB.ExtendModeY = Direct2D1.
ExtendMode.Wrap
.Transform = AffineMatrix(60, -30)
Dim R
As
New Direct2D1.
RectF(-195, 195, 65, 455)
Dim SB
As Direct2D1.
SolidColorBrush = _renderTarget.CreateSolidColorBrush(
New Direct2D1.
ColorF(0, 0, 0))
.DrawRectangle(R, SB, 3)
.FillRectangle(R, BB)
.EndDraw()
End
With
End
If
End
Sub
Public
Function AffineMatrix(angelX
As
Single, angelY
As
Single)
As Direct2D1.
Matrix3x2F
Dim M
As
New Direct2D1.
Matrix3x2F
M.M11 =
Math.Cos(angelY *
Math.PI / 180)
M.M12 =
Math.Sin(angelY *
Math.PI / 180)
M.M21 =
Math.Sin(angelX *
Math.PI / 180)
M.M22 =
Math.Cos(angelX *
Math.PI / 180)
M.M31 = 0
M.M32 = 0
Return M
End
Function
Public
Function Multiply(M1
As Direct2D1.
Matrix3x2F, M2
As Direct2D1.
Matrix3x2F)
As Direct2D1.
Matrix3x2F
Dim S1
As
New Drawing2D.
Matrix(M1.M11, M1.M12, M1.M21, M1.M22, M1.M31, M1.M32)
Dim S2
As
New Drawing2D.
Matrix(M2.M11, M2.M12, M2.M21, M2.M22, M2.M31, M2.M32)
S1.Multiply(S2, Drawing2D.
MatrixOrder.Append)
Dim S()
As
Single = S1.Elements
Return
New Direct2D1.
Matrix3x2F(S(0), S(1), S(2), S(3), S(4), S(5))
End
Function
Public
Function Invert(M1
As Direct2D1.
Matrix3x2F)
As Direct2D1.
Matrix3x2F
Dim S1
As
New Drawing2D.
Matrix(M1.M11, M1.M12, M1.M21, M1.M22, M1.M31, M1.M32)
If S1.IsInvertible =
True
Then S1.Invert()
Dim S()
As
Single = S1.Elements
Return
New Direct2D1.
Matrix3x2F(S(0), S(1), S(2), S(3), S(4), S(5))
End
Function
End
Class
看看效果圖吧
![image image](http://static.javashuo.com/static/loading.gif)
效果仍是不錯的吧。把本來正方形的圖案轉換成傾斜視角的圖案。這個效果像不像一些遊戲的效果?這個就是仿射轉換(AffineTransform)的功勞。(傾斜轉換(SkewTransform)達不到這樣的效果)
下面再給這個畫面添加一我的物,人物以下:
![219 219](http://static.javashuo.com/static/loading.gif)
因爲已經把座標系改爲仿射座標,因此在繪製時,先要進行逆轉換。因而用到以前的Invert(逆轉換函數)和Multiply(矩陣乘法,實現複合轉換)。代碼以下:
Public
Class
clsDirect2DSample15
Inherits
clsDirect2DSample14
Public
Shadows
Sub Render()
If
Not _renderTarget
Is
Nothing
Then
With _renderTarget
.BeginDraw()
.Clear(
New Direct2D1.
ColorF(
Color.Chocolate.ToArgb))
Dim B
As Direct2D1.
D2DBitmap = LoadBitmapFromFile(
"218.png")
Dim Man
As Direct2D1.
D2DBitmap = LoadBitmapFromFile(
"219.png")
Dim BB
As Direct2D1.
BitmapBrush = _renderTarget.CreateBitmapBrush(B)
BB.Transform = Direct2D1.
Matrix3x2F.Scale(0.25, 0.25)
BB.ExtendModeX = Direct2D1.
ExtendMode.Wrap
BB.ExtendModeY = Direct2D1.
ExtendMode.Wrap
.Transform = AffineMatrix(60, -30)
Dim R
As
New Direct2D1.
RectF(-195, 195, 65, 455)
Dim SB
As Direct2D1.
SolidColorBrush = _renderTarget.CreateSolidColorBrush(
New Direct2D1.
ColorF(0, 0, 0))
.DrawRectangle(R, SB, 3)
.FillRectangle(R, BB)
PaintMan(Man,
New Direct2D1.
Point2F(40, 140), .Transform)
.EndDraw()
End
With
End
If
End
Sub
Public
Sub PaintMan(man
As Direct2D1.
D2DBitmap, point
As Direct2D1.
Point2F, T
As Direct2D1.
Matrix3x2F)
Dim F
As
New Direct2D1.
RectF(point.X - 200, point.Y - 200, man.PixelSize.Width + point.X + 200, man.PixelSize.Height + point.Y + 200)
Dim B
As Direct2D1.
BitmapBrush = _renderTarget.CreateBitmapBrush(man)
B.Transform = Multiply(Invert(T), Direct2D1.
Matrix3x2F.Translation(point.X, point.Y))
_renderTarget.FillRectangle(F, B)
End
Sub
End
Class
示例代碼的效果以下:
![image image](http://static.javashuo.com/static/loading.gif)
有點遊戲畫面的雛形了吧。
不過,這個代碼僅僅是舉例,來講明轉換(Transform)的效果。實際上,背景和人物放在不一樣的圖層裏來顯示,可能代碼會簡單一些。可是,繪製在一個圖層裏,能夠作到座標的統一,不須要進行座標的轉換。就看你的取捨了。