(轉載請註明出處)
這節就來一個簡單的自定義特效作爲概念的入門。
首先需要頭文件
#include <d2d1effectauthor.h>
#include <d2d1effecthelpers.h>
爲了實現一個自定義的D2D特效,需要繼承ID2D1EffectImpl並實現其接口。
好了,這裏因爲僅僅是介紹一下概念,所以這次的自定義特效就定爲下陰影吧,微軟也是這麼幹的。
實現就用現成的,因爲特效的輸入也能是特效。
Transform: 暫時稱爲"轉變"吧,一個轉變表示對圖像進行一次操作
Transform Graph: 暫時稱爲"轉變邏輯圖"吧 就是將各個轉變組織起來的順序,因爲特效是單輸出多輸入的,
所以內部應該是樹
之前一節我們知道利用一個GUID即可創建一個特效,所以之前我們應該註冊特效:
使用ID2D1Factory1::RegisterEffectFromString進行特效註冊
參數1: 需要註冊的自定義GUID
參數2: 一個XML字符串,用來形容本效果
參數3: 綁定的控制變量數組
參數4: 數組長度
參數5: 創建對象對調函數的指針,建議是私有化的靜態成員方法
生成GUID的工具VS Express for Windows Desktop自帶了。
工具-創建GUID
即可創建一個GUID。使用DEFINE_GUID的話,建議儘可能的推遲"initguid.h"文件的包含地點,否則會鏈接失敗
一個XML的例子如下:
// 第一行不能有\n不知道是不是bug
const WCHAR* pszXml = LR"xml(<?xml version = "1.0" ?>
<Effect>
<!--系統屬性 請注意 name不支持漢字-->
<Property name = "DisplayName" type = "string" value = "下陰影效果" />
<Property name = "Author" type = "string" value = "dustpg" />
<Property name = "Category" type = "string" value = "Transform" />
<Property name = "Description" type = "string" value = "如題" />
<Inputs>
<Input name = "Source" />
</Inputs>
<!--自定義屬性 可以寫 對輸入變量的 說明-->
<Property name='Offset' type='vector2'>
<Property name='DisplayName' type='string' value='Image Offset'/>
<Property name='Min' type='vector2' value='(-1000.0, -1000.0)' />
<Property name='Max' type='vector2' value='(1000.0, 1000.0)' />
<Property name='Default' type='vector2' value='(0.0, 0.0)' />
</Property>
</Effect>
)xml";
使用C++11的原聲字符串很方便創建腳本、XML等字符串。
格式都不用說了,一看就明白。自定義屬性不是隨意的,請參考如下
(有字節數組不就是隨意的麼╮( ̄▽ ̄)╭ )
Data type | Corresponding XML value |
---|---|
PWSTR | string |
BOOL | bool |
UINT | uint32 |
INT | int32 |
FLOAT | float |
D2D_VECTOR_2F | vector2 |
D2D_VECTOR_3F | vector3 |
D2D_VECTOR_4F | vector4 |
D2D_MATRIX_3X2_F | matrix3x2 |
D2D_MATRIX_4X3_F | matrix4x3 |
D2D_MATRIX_4X4_F | matrix4x4 |
D2D_MATRIX_5X4_F | matrix5x4 |
BYTE[] | blob |
IUnknown* | iunknown |
ID2D1ColorContext* | colorcontext |
CLSID | clsid |
Enumeration (D2D1_INTERPOLATION_MODE, etc.) | enum |
控制變量綁定:
需要: 名稱、讀回調接口、寫回調接口。
兩個接口是成員方法。
比如我們XML寫的是一個綁定控制變量: 二維向量
const D2D1_PROPERTY_BINDING bindings[] = {
D2D1_VALUE_TYPE_BINDING(L"Offset", &SetOffset, &GetOffset),
};
2個方法聲明如下:
HRESULT SetOffset(D2D_VECTOR_2F offset);
D2D_VECTOR_2F GetOffset();
創建函數 裏面動態生成一個對象即可,就不多說了
這樣就能創建一個特效了,接下來就是實現 ID2D1EffectImpl 接口,
ID2D1EffectImpl繼承於IUnknown,這個老夥計的3個接口怎麼實現就不說了。
ID2D1EffectImpl::Initialize 初始化對象,創建對象後就會調用這個方法。
用來初始化、準備數據,設置最初的轉變邏輯圖等。
ID2D1EffectImpl::SetGraph 當輸入數量改變時會被調用,大多數特效都是一個輸入對象,
僅僅需要返回E_NOTIMPL即可。複數個的就需要自行處理
ID2D1EffectImpl::PrepareForRender 再被渲染前會被調用,比如我們修改了高斯模糊的程度值,
爲了改變輸出,自然需要準備一下。
我們這裏修改偏離量即可
實現設置邏輯圖:
如果只有一個轉變,則僅僅簡單地使用ID2D1TransformGraph::SetSingleTransformNode即可。
但是我們的下陰影有兩個轉換節點:D2D自帶的陰影特效與平移轉換。
初始化方法有個提供了一個ID2D1EffectContext參數,這個能用
ID2D1EffectContext::CreateEffect創建已經註冊的特效,還有一些內建的轉變,就不贅述了。
添加轉變節點:
使用ID2D1TransformGraph::AddNode先將所有轉變節點添加進來...這是靜態鏈表,哦不,靜態樹的實現?
ID2D1TransformGraph::ConnectToEffectInput 將本效果的指定輸入端 連接到 指定轉變的指定輸入端
ID2D1TransformGraph::ConnectNode 將前者的輸出端 連接到 後者指定的輸入端
ID2D1TransformGraph::SetOutputNode 將指定轉變的輸出端 作爲 本特效的輸出端
例子: 熟悉連接各個節點
比如我們要實現一個高級的下陰影——能夠將原輸入圖像顯示出來
連接圖(假設對象已經創建並且已經被AddNode):
pTransformGraph->ConnectToEffectInput(0, pShadow, 0);
pTransformGraph->ConnectNode(pShadow, p2DAffineTransform, 0);
pTransformGraph->ConnectNode(p2DAffineTransform, pComposite, 0);
pTransformGraph->ConnectToEffectInput(0, pComposite, 1);
pTransformGraph->SetOutputNode(pComposite);
更復雜的例子:
連接圖(假設對象已經創建並且已經被AddNode):
pTransformGraph->ConnectToEffectInput(0, pArithmeticComposite, 0);
pTransformGraph->ConnectToEffectInput(0, pShadow, 0);
pTransformGraph->ConnectNode(pShadow, pCompositeV1, 0);
pTransformGraph->ConnectNode(pShadow, pPointSpecular, 0);
pTransformGraph->ConnectNode(pPointSpecular, pCompositeV1, 1);
pTransformGraph->ConnectNode(pShadow, p2DAffineTransform, 0);
pTransformGraph->ConnectNode(pCompositeV1, pArithmeticComposite, 1);
pTransformGraph->ConnectNode(pShadow, p2DAffineTransform, 0);
pTransformGraph->ConnectNode(pArithmeticComposite, pCompositeV2, 0);
pTransformGraph->ConnectNode(p2DAffineTransform, pCompositeV2, 1);
pTransformGraph->SetOutputNode(pCompositeV2);
好了,下陰影的例子就提供在下面。
只有陰影...
下載地址:點擊這裏