首页 > 代码库 > Direct2D 1.1 开发笔记 特效篇(二) 简单的自定义特效
Direct2D 1.1 开发笔记 特效篇(二) 简单的自定义特效
(转载请注明出处)
这节就来一个简单的自定义特效作为概念的入门。
首先需要头文件
#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 = http://www.mamicode.com/"下阴影效果" />>
使用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);
好了,下阴影的例子就提供在下面。
只有阴影...
下载地址:点击这里
Direct2D 1.1 开发笔记 特效篇(二) 简单的自定义特效