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 = "下阴影效果" />
    <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);

好了,下阴影的例子就提供在下面。

只有阴影...

下载地址:点击这里

时间: 2025-01-09 14:39:24

Direct2D 1.1 开发笔记 特效篇(二) 简单的自定义特效的相关文章

【Kinect开发笔记之(二)】Kinect for windows发展历程

新版本SDK和旧版本的SDK完全兼容,如果您之前安装过旧版本的,可以直接安装新版本的SDK,但是如果您之前的开发版本是Beta版的,则需要卸载之后再安装新版本.在Kinect for Windows SDK 1.0版本中,SDK和示例文件是打包一起安装的.而在之后的版本,为了可以分别升级,微软把这两者分开独立为Kinect for Windows SDK和Kinect for Windows Developer Toolkit这两部分,所以需要分别下载安装, Kinect for Windows

Direct2D 1.1 开发笔记 特效篇(一) 使用D2D特效

(转载请注明出处) 问! 为什么使用D2D 1.1版本,而不是1.0版本? 答: D2D 特效 在Direct2D 1.1 中,提供了ID2D1Effect接口,让程序员使用硬件加速的实时特效.这几乎就是使用D2D 1.1的绝对理由. 其他什么 CommandList 什么的,完全不知道嘛╮( ̄▽ ̄)╭ 头文件就是d2d1effects.h啥的,不过还要请链接"dxguid.lib"静态库 使用ID2D1DeviceContext::CreateEffect创建D2D特效, 使用ID2

Android开发笔记(九十七)图片的特效处理

图片特效用到的函数 本文讲述的图片特效处理包括:怀旧.光照.光晕.底片.浮雕.模糊.锐化.黑白.冰冻.素描,所有这些特效都是基于一定的算法,对图像每个点的RGB值进行计算,并汇总所有点的计算结果生成新图片. 特效处理主要用到Bitmap类的三个方法: createBitmap : 创建一张新图片. getPixels : 从指定图片中获取所有点的像素数组. setPixels : 对指定图片设置所有点的像素数组. 图片怀旧效果 现实生活中的老相片都是泛黄的,而黄色又是由绿色和红色混合而成,所以怀

Android开发笔记(一百二十)两种侧滑布局

SlidingPaneLayout SlidingPaneLayout是Android在android-support-v4.jar中推出的一个可滑动面板的布局,在前面<Android开发笔记(一百零一)滑出式菜单>中,我们提到水平布局时的LinearLayout无法自动左右拉伸,必须借助于手势事件才能拉出左侧隐藏的布局,现在SlidingPaneLayout便是为了解决LinearLayout无法自动拉伸的缺陷.只要我们在布局文件的SlidingPaneLayout节点下定义两个子布局,那么

Direct2D 1.1 开发笔记 特效篇(三) 简单的像素着色器特效

(转载请注明出处) 这次我们实现一个自定义的转变. 实现Direct2D 自定义转变Shader Models需要HLSL(High Level Shading Language)的实现. HLSL是Shader的一种实现,但是HLSL只能在D3D中使用,所以有点蛋疼. Shader被描述为显卡执行的小段程序,能够高效(并行)地执行. 没学过?没关系,笔者也没有,但是详细的不会在这里说明(你TM逗我(╯‵□′)╯︵┴─┴),请到官网中看看. D2D 特效能用 HLSL 的  4.0 及其以上版本

Direct2D 1.1 开发笔记 特效篇(四) 图形调试

 (转载请注明出处) 如同上节所述,这节讲讲怎么调试图形. 很可惜,微软并没有对VS Express 2013 for Windows Desktop(下面简称WDExpress)添加图形调试功能. 对于付费版的VS(VS2013 pro对于学生与教员可以免费获取)则带有图形调试功能: 调试--图形--启用诊断 即可. 对于免费版,则有VS Express 2013 for Windows(下面简称VSWinExpress)带有图形调试功能. 幸运地,一个付费版.WDExpress与VSWi

JavaScript笔记基础篇(二)

基础篇主要是总结一些工作中遇到的技术问题是如何解决的,应为本人属于刚入行阶段技术并非大神如果笔记中有哪些错误,或者自己的一些想法希望大家多多交流互相学习. 1.ToFixed()函数 今天在做Birt报表时, 要显示一列百分比的数据,但因一些特别的原因,不能使用使用百分比样式,即如果数据是0.9538不能显示成“95.38%”的样式,必须显示成“95.38”. 开始时想使用javascript的内置函数Math.round(),可Math.round()只能显示为整数,而不能保留小数. 再网上搜

iOS开发笔记 - 语言篇之Swift

?2014年的苹果全球开发者大会(WWDC),当Craig Federighi向全世界宣布"We have new programming language"(我们有了新的编程语言)的时候,全场响起了最热烈和持久的掌声,伴随着掌声到来的语言叫Swift.接下来Craig Federighi更是毫不掩饰的告诉大家,Swift将成为主宰iOS和Mac开发的新语言,甚至是整个软件行业中最举足轻重的语言. ??Swift正如它的名字那样迅速.敏捷,但这并不是它的全部.Swift是一个博采众长的

iOS开发笔记 - 网络篇

计算机网络基础 ??计算机网络是多台独立自主的计算机互联而成的系统的总称,最初建立计算机网络的目的是实现信息传递和资源共享. ??如果说计算机是第二次世界大战的产物,那么计算机网络则是美苏冷战的产物.20世纪60年代初期,美国国防部领导的ARPA提出研究一种崭新的.能够适应现代战争的.生存性很强的通信系统并藉此来应对苏联核攻击的威胁,这个决定促使了分组交换网的诞生,也奠定今天计算机网络的原型,这是计算机网络发展史上第一个里程碑式的事件. ??第二个里程碑式的事件是20世纪80年代初,国际标准化组