Quantcast
Channel: 英特尔开发人员专区文章
Viewing all 154 articles
Browse latest View live

竞赛获胜者将带有百科全书的增强现实整合至 ARPedia*

$
0
0

作者:Garret Romaine

未来的界面已经在某处的实验室中或测试屏幕上进行实验或测试,并随时等待着转化为充分开发的实例和演示。 事实上,CES 2014 宣布,英特尔® 感知计算第二阶段挑战赛中创造性用户体验类的获奖者便很好的明证。 Zhongqian Su 和一群研究生使用英特尔® 感知计算软件开发套件Creative Interactive Gesture Camera Kit将增强现实(AR)和一部普通的百科全书整合到 ARPedia* 中 — 增强现实与维基百科*的完美结合。 ARPedia 是一款新型的知识库,支持用户通过手势而非敲击键盘的方式来使用。

来自北京工业大学的六人团队在两个月内使用多种工具开发了这款应用。 该团队使用了 Maya* 3D创建 3D 模型,使用 Unity* 3D渲染 3D 场景和开发应用逻辑,然后使用英特尔感知计算软件开发套件 Unity 3D 插件(包含在软件开发套件中)将所有组件结合起来。 该演示结合 3D 模型和动画视频,创建了一种与虚拟世界交互的新方式。 该款应用鼓励用户通过移动身体,使用手势、语音和触摸在未知世界中进行数字开发,未来工作将会非常令人期待。

关于恐龙


借助 AR 视觉效果,ARPedia 相当于一款编写和体验故事的游戏。 随着用户逐渐习惯无缝交互式体验,许多技术开始创建交互式体验,即使这种交互式体验非常简单。 在一款 PC 游戏中,普通的鼠标和键盘或触摸屏,是与应用交互的常见方式。 但是,ARPedia 没有使用上述任何一种方式。 在一款 AR 应用中,自然用户界面非常重要。 ARPedia 用户能够通过裸手手势和面部移动来控制动作,这要归功于 Creative Senz3D* 摄像头。 许多有趣的手势能够帮助提高游戏体验,如抓、挥、点、抬和按。 这些手势让玩家成为游戏以及虚拟恐龙世界的真正控制者。


图 1:ARPedia* 结合了增强现实和基于维基的百科全书,支持用户使用手势导航界面。

组长 Zhongqian Su 曾在以前的一个任务中使用小型雷克斯霸王龙的角色创建过教学应用,因此,他让这位众所周知的恐龙作为 ARPedia 应用的主角。 玩家通过手部运动伸手抵达并摘取小型的恐龙图片,然后将其放在屏幕的各个点上。 根据恐龙所放置的位置,用户可以了解该生物的饮食、习惯和其他特征。

图 2:用户与小雷克斯霸王龙互动来学习化石、古生物学和地质学知识。

据团队成员 Liang Zhang 表示,该团队在使用该恐龙 3D 模型之前便针对教育市场编写了一款 AR 应用。 虽然,他们已经有一款应用作基础,但是还需要根据竞赛的要求做大量的调整。 例如,他们已经完成的摄像头使用了 3D 技术,因此他们需要重新编写该代码(见图 3),以便与更新的 Creative Interactive Gesture Camera Kit 相融。 这同时也意味着需要快速达到英特尔感知计算软件开发套件的性能。


bool isHandOpen(PXCMGesture.GeoNode[] data)
	{
		int n = 1;
		for(int i=1;i<6;i++)
		{
			if(data[i].body==PXCMGesture.GeoNode.Label.LABEL_ANY)
				continue;
			bool got = false;
			for(int j=0;j<i;j++)
			{
				if(data[j].body==PXCMGesture.GeoNode.Label.LABEL_ANY)
					continue;
				Vector3 dif = new Vector3();
				dif.x = data[j].positionWorld.x-data[i].positionWorld.x;
				dif.y = data[j].positionWorld.y-data[i].positionWorld.y;
				dif.z = data[j].positionWorld.z-data[i].positionWorld.z;
				if(dif.magnitude<1e-5)
					got = true;
			}
			if(got)
				continue;
			n++;
		}
		return (n>2);
	}

图 3:ARPedia* 重新编写了其摄像头代码,以配合 Creative Interactive Gesture Camera 使用。

Zhang 表示,幸运的是,他的公司非常热衷于在学习新技术方面投入时间和精力。 他表示:“我们已经开发了许多款应用。 我们时刻关注我们公司中能够使用的新软硬件改进。 在此次竞赛前,我们使用了 Microsoft Kinect* 的自然身体交互。 当我们发现该摄像头时,我们感到非常兴奋,并希望试一试。 我们认为这次竞赛也能够为我们提供改进技术技能的机会,所以,为什么不试一试呢?”

先行的明智决策


由于竞赛的时间范围有限,该团队不得不加快采用新技术的速度。 Zhang 花费了两周的时间学习英特尔感知计算软件开发套件,然后该团队将 Zhang 能想到的交互技术尽可能多地设计进去。

同时,编剧开始编写团队能够进行编码的故事和可行场景。 他们满足并探讨这些选择,并由 Zhang 根据自己的软件开发套件知识指出优势和劣势。 他对技术细节有着充分的了解,从而能够制定明智的决策,因此,该团队放心地选择了他描述为“...最佳的故事和最有趣、最适合的交互。”

Zhang 表示,他们以前的决策中最重要的一个决策是让玩家充分参与到游戏中。 例如,在早期的孵化阶段中,玩家可以担任扮演上帝的角色,执行创建地球以及下雨、日出等操作。 玩家需要设置和学习许多手势操作。

在另一个阶段中,玩家需要抓恐龙。 Zhang 对系统进行了设置,这样用户的手中可以拿一片肉,然后恐龙能够上前把肉衔起(图 4)。 该动作可以让玩家与恐龙进行互动,并建立参与。 他表示:“我们希望让玩家一直沉浸在虚拟世界中。”

图 4:喂食小恐龙能够让用户沉浸其中并能创建互动。

但是,向前推进这些计划需要做更多的工作。 该演示包括许多新的手势需要用户学习。 Zhang 表示:“当我与 CES 上在英特尔展台上玩这款游戏的人交谈时,发现他们不太清楚如何玩这款游戏,因为每个阶段都有各种等级的手势。 我们发现它们不像我们原来设想的那么直观,这让我们决定,当我们加入新的交互式方法时,该设计必须更加直观。 我们进行下一个项目时,肯定会将其牢记于心。”

ARPedia 团队介绍了两种主要手势。 一种是“双手打开”,另一种是“单手打开,手指伸开。” 双手打开手势,可用来打开应用,是一种简单直接的编码方式。 但是,编写第二种手势需要更多工作。

图 5:该团队努力确保该摄像头不会将手腕检测为手掌上的一点。

Zhang 解释道:“最初“打开手”的姿势并不太准确。 有时,手腕会被检测为手掌上的一点, 拳头会被检测为一根手指,然后系统将会把其识别为“打开”,这是错误的。 因此,我们设计了一种新的打开手的姿势,在这种姿势中,至少伸出两根手指才会识别为打开手。 然后,他们在屏幕上添加了文本提示,引导用户了解附件(图 5)。

英特尔® 感知计算软件开发套件


ARPedia 团队使用了 2013 版英特尔感知计算开发套件,并特别指出摄像头校准、应用调试和语音识别支持、面部分析、近距离深度跟踪和 AR 的出色易用性。 它支持多个感知计算应用共享输入设备,并可在 RGB 和深度摄像头打开时提供一个隐私通知来通知用户。 软件开发套件能够帮助用户轻松添加更多使用模式,添加新的输入硬件,支持新的游戏引擎和定制算法,并支持新的编程语言。

该实用程序包括 PXCUPipeline(C) 和 UtilPipeline(C++) 等 C/C++ 组件。 这些组件主要用于设置和管理管线会话。 框架和会话端口包括适用于 Unity 3D、处理、其他框架和游戏引擎的端口,以及适用于 C# and Java* 等编程语言的端口。 软件开发套件接口包括核心框架 API、I/O 分类和算法。 感知计算应用可通过三种主要功能块与软件开发套件进行交互。

Zhang 表示:“英特尔[感知计算]软件开发套件非常有帮助。 我们在开发这款应用的时候没有遇到任何问题。 我们能够在非常短的时间内完成大量的工作。”

英特尔® RealSense™ 技术

全球的开发人员都在学习英特尔® RealSense™ 技术。 英特尔在 CES 2014 上宣布,英特尔 RealSense 技术是以前的 英特尔® 感知计算技术的新名称和品牌。 该直观新用户界面采用英特尔在 2013 年推向市场的手势和语音等功能。 借助英特尔 RealSense 技术,用户将会获得其他的新功能,包括扫描、修改、打印和以 3D 形式共享,以及 AR 接口中的主要优势。 借助这些新功能,用户可以在游戏和应用中使用高级手、指感应技术,自然地操作和播放扫描的 3D 对象。

Zhang 现在能够直接看到其他开发人员如何使用 AR 技术操作。 在 CES 2014 上,他了解了来自全球的演示。 虽然每个演示都是独一无二的,并希望达到不同的目标,但是他仍然从中发现了快速发展 3D 摄像头技术所带来的优势。 “在软件开发套件中包含手势检测非常有帮助。 人们仍然能够以不同的方式使用摄像头,但是软件开发套件已经为他们提供了广泛的基础。 我建议开发人员使用该技术开发自己的项目,并寻找功能充分地开发其理念。”

借助高级手—指追踪,开发人员可支持其用户使用复杂的 3D 操作以更高的精度、更简单的命令来控制设备。 借助自然语言语音技术和精确的面部识别,设备能够更好地了解其用户的需求。

深度感应可带来更逼真的游戏体验,准确的手-指追踪可为任何虚拟冒险带来更卓越的追踪。 游戏将变得更加逼真和有趣。 借助 AR 技术和手指感应技术,开发人员将能够吧真实世界和虚拟世界融为一体。

Zhang 相信即将推出的英特尔 RealSense 3D 摄像头将会非常适合他所熟悉的应用场景。 他表示:“据我所知,它将更加出色 — 更准确、具备更多功能、更直观。 我们非常期待这款产品。 此外,它还会加入 3D 面部追踪和其他的出色特性。 它是首款面向笔记本电脑,并用作动作感应设备的 3D 摄像头,但是它不同于 Kinect。 此外,它还能够提供与内部 3D 摄像头一样的功能。 我认为,新的英特尔摄像头是支持制造商向笔记本电脑和平板电脑集成的更出色的设备。 此外,作为一款微型用户接口设备,它还具备很好的便携性优势。 借助该款摄像头,将来我们肯定能够开发出许多出色的项目。”

Maya 3D


ARPedia 团队使用 Maya 3D 模拟软件继续开发其知名的小型、逼真的模型 — 小雷克斯霸王龙。 构建合适的模型(包括逼真的动作和精细的色彩),应用的其他部分便水到渠成。

Maya 是创建 3D 计算机动画、建模、模拟、渲染等的黄金标准。 它是一款高可扩展的产品平台,可支持下一代显示技术,加开建模工作流程的速度和处理复杂数据。 该团队尚未使用过 3D 软件,但是他们使用过 Maya,并能够轻松地更新并与其现有的图形相集成。 Zhang 表示,其团队又额外花费时间进行了图形的开发。 他表示:“我们花费了将近一个月的时间设计和修改图形,以便让一切更完美和提高交互方式。”

Unity 3D


该团队选择 Unity 引擎作为其应用的基础。 Unity 是一款强大的渲染引擎,可用于创建交互式 3D 和 2D 内容。 Unity 工具集既是一款应用构建程序,也是一款应用开发工具,其特点是直观、易于使用且支持多平台开发。 无论对于初用者还是已经使用过该产品的用户,它都是开发仿真、休闲和大型游戏以及面向 web、移动或控制台的应用的理想解决方案。

Zhang 表示,我们毫不犹豫地选择了 Unity。 他表示:“我们开发所有的 AR 应用都是使用 Unity,包括这一款。 我们了解这款工具,并且相信它能够做到我们需要的一切事情。” 他能够将网格作为专有 3D 应用文件快速、轻松地从 Maya 导入,既节省时间又节省精力。

今天的信息,明天的游戏


ARPedia 为未来的工作提供了许多有意义的角度。 对于刚起步的团队而言,该团队认为游戏和其他应用中拥有巨大的机遇,你可以借鉴其在英特尔感知计算挑战赛中的成果。 Zhang 表示:“我们与许多感兴趣的组织进行过交谈。 他们也希望我们进一步对这一版本进行完善。 希望我们能够在市场上找到一席之地。 我们将会向游戏中加入更多的恐龙,并引进有关这些恐龙的所有知识来吸引更多用户。 它是一个有趣的环境,我们将围绕其设计更多有趣的交互。”

“此外,我们还准备设计一款宠物游戏,在这款游戏中,用户可以喂养自己的虚拟恐龙。 他们可以拥有自己的特定收集,还可以拿来向彼此展示。 我们还将把它设计成一款网络游戏。 我们准备在新版本中加入更多场景。”

该团队的胜出让大家非常惊讶,因为他们并不熟悉全球范围内其他开发团队的工作。 Zhang 表示“我们不了解其他人的工作。 我们只着眼自己的事情,没有太多机会了解其他人在做什么。” 现在,他们已经知道了自己的局限,并做好充分的准备迎接下一步挑战。 “此次竞赛为我们提供了证明自己的动力,以及与其他开发人员比较和交流的机会。 我们非常感谢英特尔为我们提供的这次机会。 现在,我们更加了解全球范围内的主要技术,并且在未来开发增强现实应用时将会更有信心。”

资源


英特尔® 开发人员专区
英特尔® 感知计算挑战赛
英特尔® RealSense™ 技术
英特尔® 感知计算软件开发套件
查看感知计算文档中的兼容性指南,确保您现有的应用能够使用英特尔® RealSense™ 3D 摄像头。
英特尔® 感知计算软件开发套件 2013 R7 版本注释
Maya* 软件概述
Unity*


新版英特尔®XDK为您带来了哪些新特性?

$
0
0

现在开发者可以简便地整合第三方服务的API来使应用变现或整合后端服务来创建内容更加丰富多彩的应用。英特尔®XDK使开发者能够便捷地在应用中加入上百种开源的第三方Cordova*插件,以及Android*, iOS*, Window 8*平台上的各种专有插件。


新建项目

一体式工作流,让你的App从创意迸发到打包发布一气呵成:

  • 多合一的解决方案

  • 使用多种方式开始创建你的App


项目管理视图

一个页面轻松管理你的所有项目:

  • 使用更多方式配置你的项目属性,自定义项目信息

  • 使用丰富的Cordova*插件来配置你的项目

  • 同时管理多个项目

 

API和插件管理

高效地接入和管理API:

  • 提供所有操作系统平台上的Cordova* 3.5基础容器,包括上百种Cordova* API和Intel XDK API

  • 提供对Cordova* 3.5,PhoneGap*和Github* repo等第三方插件的支持

  • 允许自定义的第三方插件

 

新的Services Tab, 成就精彩的App体验

利用应用变现和广告等多种服务创建内容丰富的应用:

  • Google*和Apple*的应用内支付等应用变现服务

  • 使用第三方插件的Google* AdMob, Facebook*, 和Urban* Airship

  • Google* Analysis,以及使用OAuth* 2协议的Dropbox*文件存储和Foursquare*

  • Kinvey* 数据存储

  • App Designer内置的Google*地图插件

 

代码实时预览

用更简便的应用开发方式节省你的时间:

  • 将代码改动实时呈现在浏览器或设备

  • 利用App Preview 实时测试和编辑你的应用

  • 允许开发者即时看到代码改动

 

丰富的应用商店

一次开发,多个商店同时发布:

  • 打包应用并提交到更多应用商店

  • 为多种设备形式部署你的应用

  • 新增Firefox*应用商店

 

欲下载最新版XDK,请前往 http://xdk.intel.com

您可关注英特尔XDK官方微博 http://weibo.com/xdktool 即时了解我们的信息,或扫一扫下面的二维码关注我们的微信账号:

让年轻读者加入英特尔® 感知计算 — 开发面向一体机的 Clifford’s Reading Adventures

$
0
0

Download PDF

简介

本文介绍了如何开发 Clifford’s Reading Adventures—Scholastic Interactive LLC 面向儿童推出的一套交互式教育游戏。 新款游戏中的沉浸式手势和语音体验是通过英特尔® 感知计算 SDK 2013 来实现的。 我们讨论了结合感知计算捕获儿童手势和音质的新方法、针对 SDK 的故障排除策略以及为支持便携式一体机所做的考量。


图 1. Clifford The Big Red Dog*

教育游戏概念

Scholastic Interactive LLC 是 Scholastic 旗下的公司,是一家全球性的儿童出版、教育和媒体公司。 Scholastic Interactive 的目标是让儿童游戏寓教于乐。 Scholastic 对于使用感知计算和手势技术开发儿童教育游戏这一新领域非常感兴趣,因为这种方式非常直观, 儿童无需学习即可操作。 将感知计算平台与其语音和手势技术相结合,加入 Clifford 与他朋友的冒险故事,能够为 3 岁以上的儿童提供一种简单、自然的方式,让他们与故事材料轻松互动。

在这个由四个交互式单元构成的 Clifford 系列故事中,玩游戏的人可以观看每个冒险故事,使用电脑上的语音和触摸屏功能与故事互动。 故事将请求孩子们通过手势和声控活动用各种方法“帮助” Clifford,从而邀请他们参与其中。


图 2. Clifford's Reading Adventures 菜单

交互式体验学习

Clifford中,Scholastic 发现了向其最年轻的读者提供交互式技术的大好机遇,这些年轻读者能够真实地看到 Clifford 对他们的声音和动作做出反应。 在精彩的故事情节中,儿童观看每个冒险故事的动画片段,通过触摸或口头说出答案来与人物角色及其活动进行积极互动。 儿童在玩采用触摸和手势功能的游戏时还可加快故事情节的进度。 每个游戏基于早期核心读写技能,可根据需要多次重复。

英特尔感知计算 SDK 2013 可提供 API、样本和教程,为体验游戏的儿童解释使用应用中的手势和声音所需的传感器。 语音识别、近距离手和手指跟踪、面部分析、增强现实和背景减除等 SDK 的核心功能支持软件开发人员将这些功能与最新的平板电脑、英特尔超极本™ 电脑和一体机上的应用快速集成。 使用麦克风、摄像头、触摸屏以及方向和位置功能(现常用与平板电脑、变形笔记本电脑和一体机),开发人员能够构建沉浸式效果更强的应用。


图 3. 英特尔® 感知计算软件开发套件

开发团队

Scholastic 就游戏概念、交互式活动和主要的儿童易用性问题面试了许多开发团队。 最终,Scholastic 选择了与 Symbio合作,因为他们的团队曾开发并实施过手势和语音识别,而且他们在儿童教育、游戏和易用性方面拥有丰富的经验。

使用英特尔® 感知计算平台进行开发

根据儿童的动作、手势和声音调整感知计算技术面临几大挑战。 Scholastic 的一般流程是对每种模型进行广泛测试,从而了解游戏设计是否适当以及游戏等级是否能实现。 该测试可帮助团队确认测试玩家(目标年龄儿童)遇到的挑战,这样便可设计和开发适合此年龄段的解决方案。

在开发阶段中有几个方面需要感知计算开发人员特别注意。 以下是从 Clifford 应用开发中得到的一些要点。

 

校准语音识别

语音识别需要多步校验和过滤才能够提供可接受的性能级别。 由于随着儿童的成长其声音会不断发育,尤其是 Clifford系列故事的年轻目标受众,因而应确保对语音识别进行精确校准,以辨别儿童声音和语言模式的细微差别。


图 4. 使用语音识别功能的游戏屏幕

验证并锁定手势

Clifford’s Reading Adventures中的一个游戏要求孩子帮助 Clifford 接住从“玩具树”上掉下来的玩具。 还是用手抓住屏幕上的篮筐,然后向左右来回移动来接玩具。 


图 5. Clifford 的玩具树

开发人员添加了算法检查,因而能够验证手势并将其与玩家的手锁定在一起来控制篮筐,因此它能够根据儿童的手势做出移动反应。 在测试阶段期间,年轻的玩家能够高度参与,尽兴游戏,并能很好地对接玩具计时。 在测试之前,在开发实验室中进行实验时,开发人员误认为儿童对接玩具的控制与成人评估者一样。 研究儿童手势的特点为开发人员带来许多学习机会,这要求他们重新思考游戏的设计,以满足低龄儿童手势不够精确这一特征的要求。 儿童的动作较大且通常不太稳定,这带来的动作噪音对于精确捕获是很大的挑战,因为传感器很难识别并解释复杂的多重动作。 其次,建立手势模型并重复操作需要细心和适度才能达到高质量的体验。 适应儿童手势需要扩宽动作捕获区域,这样,即使手势不精确,也可以识别动作并激活所需的响应。

例如,在另一个迷你游戏中,玩家需要帮助 Clifford 从菜园里拔杂草。 开发人员没有让儿童把手伸到杂草中抓住,然后抬起手来将其拔除,而是切换为攥手/伸手的动作来象征抓草和把草丢掉。 为适应儿童的发育能力和动作而做出的变动让游戏更为成功。


图 6. 孩子使用手势帮助 Clifford 清除杂草

以下是游戏教程中用来调整玩家手势的代码,该代码会请求用户移动双手和旋转球体。 在图 7 显示的游戏中应用一些 “//exponential smoothing” 能够支持玩家更好地控制和轻松地运动。  滤波(smoothing)措施可帮助消除或至少减少游戏应忽略的玩家做出的出乎意料的动作。


图 7:球状物旋转屏幕


图 8:球状物旋转教程代码示例

排除英特尔® 感知计算软件开发套件的故障

使用 SDK 创建的沉浸式体验可支持游戏即时对玩家的动作做出响应。 这让玩家感觉到自己正在亲身实践游戏。 但是,摄像头追踪复杂手势的功能以及识别儿童发出的特定响应的语音检测功能仍有一些限制。

 

手势

感知计算的摄像头的捕获范围在距离其约 2-3 英尺的区域。 由于摄像头和对象之间的距离较短,研究人员和开发团队发现,简单的动作和小幅手势比大幅运动或复杂动作有效,后者可能会超出摄像头的范围。

我们需要通过试错法来确保手势按照需要使用。 开发团队需要注意不同的环境条件、光照以及与摄像头的距离。

根据 SDK、API 和技术,能够轻松启用基本手势,因为 SDK 中已包括了教程、示例代码和结构。 完成开发环境的设置后,您可以参照一个教程(如手指追踪示例)进行操作,以探索配合 SDK 一起使用的“传感器 - 代码”关系。


图 9. 英特尔® 感知计算软件开发套件 2013 中的手势“传感器 - 代码”关系

开发人员发现 SDK 不包含手势所需的各种坐标系。 因此,他们不得不自己找出如何让它们通过试错法。


图 10:手势坐标图像

团队最初使用 “node[8].positionImage.x/y” 方法,放弃深度信息,因为实施的手势不需要该信息。 后来,团队发现了一个更好的办法。 他们使用深度图像,搜索最近的像素以帮助有效捕获手势。 然后,他们添加了大量的滤波,以同时改进手势检测。

语音识别

游戏的语音识别功能很大程度上受到设备和场景的影响;语音识别在某些设备和情况下能够使用,但在其他设备和情况下却完全无法使用。

在游戏中,必须提示儿童重复适当的命令,这些命令通过麦克风收集。  我们需要达到准确识别 — 即使有背景噪音和游戏音乐。 语音识别可在语音检测模式下使用,用于检测您的说话内容;也可在词典模式下使用,用于检测说话内容与词典的匹配情况,用户可在游戏中对此进行定义。

首先,团队尝试了检测模式,并对其进行配置以接收任何可接收的噪音,因为幼童有时吐字不清。 但是,这没有达到预期效果。 然后,团队使用了词典模式,这在清晰的场景,即吐字清楚的情况下效果良好。 团队尝试加入词语变量,以允许接受更多的词 — 即使在吐字不清的情况下 (卖、麦、买、爱)。 但是,词典模式效果不大,因为关键词的数量越多,就越容易出现错误或失配的情况。 开发人员必须在可接受的关键词和潜在错误率之间找到一个平衡点。 在最后的应用中,团队尽量将可接受词语减到最少,以便孩子更简单地交互。

屏幕尺寸至关重要 — 一体机感知

随着触摸屏制造能力的提高,市场上出现了更大的屏幕。 屏幕尺寸扩展是 Clifford’s Reading Adventures 要展示的另一领域。 许多大型屏幕集成到一种电脑 — 一体机 (AIO) 中。

一体机由显示器(18 至 55 英寸)和构建于屏幕后方的主板构成。 它们包括高性能处理器、全高清 (HD) 分辨率 (1080p/720p) 和蓝牙* 无线键盘和鼠标,支持内置高容量电池,因而具备出色的便携性。 AIO 是 PC 中发展最快的类型之一。 其广泛普及的重要原因是 AIO 能够为您提供 PC 可提供的所有功能 — 追踪家庭开支、做作业、玩互动游戏、上网、和朋友聊天以及看电视和电影。

许多新款 AIO (pAIO) 还能够灵活添加多种功能。 pAIO 设备支持游戏和应用开发人员充分利用大屏幕空间、高性能联网能力和多点触控用户界面 (UI),将全部功能集成到一台纤薄、便携的设备中,并在倾斜和平面两种模式下使用。 内置电池可确保体验的连续性,内置无线网络支持从一个起始位置向其他位置移动。 大型 HD 显示器采用高端图形处理器,并可提供全面的多点触控用户体验 (UX)。 上述特性可帮助开发人员摆脱单用户移动设备的限制。

Clifford 开发人员看到玩家在大尺寸屏幕上玩自己的游戏感到非常兴奋,因此他们确保其游戏能够在 1920x1080 屏幕分辨率上运行良好。

总结

在开发测试过程中,该团队非常开心。 此外,通过对目标受众(儿童)做用户研究,该团队还获益良多。 我们不仅从此结构化测试中得到许多帮助,还从我们的家庭获得了大量帮助,看到家人操作最终设计出来的游戏是我们最大的嘉奖。 一位我们的高级开发人员把它带给其三岁的女儿玩,他告诉开发团队,这款游戏非常吸引她,她非常开心! 胜利!


图 11:Clifford 和快乐的小伙伴

Scholastic 团队对于能够在更多游戏中使用该技术感到非常兴奋。 Scholastic 与 Symbio 正在合作开发一款采用英特尔® RealSense™ 3D SDK 的新游戏,并计划于 2014 年秋季推出。


图 12:该款游戏全面上线

英特尔® Real-Sense™ 技术

英特尔® RealSense™ 技术首次发布于 CES 2014,是英特尔® 感知计算技术的新名称和品牌,是一款直观的用户界面 SDK,包括语音识别、手势、手和手指追踪以及面部识别等英特尔于 2013 年推出的功能。 借助英特尔 RealSense 技术,开发人员将会获得额外功能,包括扫描、修改、打印和以 3D 形式共享,以及增强现实接口中的主要优势。  使用这些新功能,用户能够使用高级手感应和手指感应技术自然操作扫描的 3D 对象。

参考资料和相关链接

关于作者

Tim Duncan 是一位英特尔工程师,被朋友们成为“Gidget-Gadget 先生”。 Tim 目前负责帮助开发人员将技术集成至解决方案,他在芯片制造和系统集成领域有着数十年的经验。 如欲对其有更多了解,请访问英特尔® 开发人员专区:Tim Duncan (英特尔)

 

声明

Scholastic Interactive LLC 提供的源代码提供了一个模型策略,可帮助在 Windows 8 平台上使用英特尔感知计算技术的应用获得指数平滑(exponential smoothing)功能。 

Scholastic 示例源代码许可

版权所有 (c) 2014, Scholastic Interactive LLC。 代码适用于 Clifford’s Reading Adventures 1.0 游戏中包含的指数平滑功能(“样本代码”)。 所有权保留。

在满足以下条件的情况下,允许以样本代码的源码和二进制形式进行再次分发或使用(作修改或不作修改):

  • 再次分发源码必须保留上述版权通知、此条件列表以及下述免责声明。
  • 若以二进制形式再次分发,必须在文档和/或其他随分发提供的材料中保留上述版权通知、此条件列表以及下述免责声明。
  • 事先未经明确的书面许可,示例代码名称 Clifford’s Reading Adventures 或本文所含的任何名称或商标、版权持有人或其附属机构的名称或示例代码贡献者的名称能够用于对此软件衍生产品的背书、推广或其他任意方式的支持。

此软件由版权持有者和献助者按“原样”提供,绝不提供其他任何明确或隐含的担保(包括,但不限于,商品适销性和或适用于特定目的适用性的担保)。 在任何情况下,版权持有者或 献助者对使用本软件而以任何方式产生之直接的、间接的、事故性的、特殊的、惩罚性的或后果性的损失(包括,但不限于,购买替代产品或服务,使用、数据或利润的减少,或者业务中断)概不承担责任,不论损失是如何造成的及根据任何责任理论(无论是按合同法、严格责任或侵权 - 包括疏忽或其它 -),即使事先被告知这种损失的可能性。  为避免疑义,本协议下所授予的权利仅限于上文中的特定软件,英特尔不授予该示例代码用户 (A) 构成或嵌入 THE CLIFFORD’S READING ADVENTURES 游戏的任何其他源代码或二进制代码,或其他软件或工具;或者 (B) 版权所有人或其附属机构的任何其他知识产权的任何许可或权利。

Clifford Artwork © Scholastic Entertainment Inc.  CLIFFORD THE BIG RED DOG 及相关标识是 Norman Bridwell 的商标。  所有权保留。

 

英特尔、 Intel 标识和 RealSense 是英特尔公司在美国和/或其他国家的商标。
版权所有 © 2014 年英特尔公司。 保留所有权利。
*其他的名称和品牌可能是其他所有者的资产。

 

在采用 TouchScript 的 Unity* 3D 中实施手势序列

$
0
0

Download PDF

By Lynn Thompson

当配置触摸目标控制一个场景中的其他元素时,应最大限度地减少控制元素所占的屏幕空间。 这样,您可以将更多超极本™ 设备的可视屏幕区域用于显示视觉活动,更少用于用户交互。 实现它的一种方法是,让触摸目标能够处理多手势组合,从而无需在屏幕上设置更多触摸目标。 比如,使用连续点击图形用户界面 (GUI) widget 来触发炮楼旋转并开火,而非使用专门的 GUI widget 开火并使用另一个 widget 旋转炮楼(或 Unity* 3D 场景中的其他资产)。

本文将介绍如何配置使用触摸目标的场景来控制第一人称控制器 (FPC)。 首先,为基本的 FPC 位置和旋转配置触摸目标;然后,将其扩大为附加功能。 附件功能可通过现有的 GUI widget 来实现,且不需要增加几何。 生成的场景将展示 Windows* 8 上运行的 Unity 3D 能够处理不同序列中使用的多手势。

配置 Unity* 3D 场景

我首先导入一个 FBX 地形资产(包括拔高的地势和树木)来设置场景,该资产是我从 Autodesk 3ds Max* 导入的。 然后,我将 FPC 放到地形中心。

我将场景主摄像头(FPC 的子对象)的景深设置为 -1。 我创建了一个专用 GUI widget 摄像头,包括一个正射投影,宽为 1,高为 0.5,以及 Don’t Clear (不清除)标记。 然后,我创建了一个 GUIWidget 层,并将其设置为 GUI widget 摄像头的裁剪蒙版。

接下来,我从专用的正投射摄像头的视角为 FPC 在场景中的操作设置了基本的 GUI widget。 在左侧,我为每根手指设置了一个范围。 左侧的小范围可将 FPC 向左侧移动,左侧的环形范围可将其向前移动,左侧中间的范围可将其向右移动,左侧的索引范围可将 FPC 向后移动。 左拇指范围可让 FPC 跳跃,并以顺时针 30 度的方向发射球形弹。

在右侧 GUI widget 中,我创建了一个立方体(通过正射投影成为正方形)。 我使用拖拽 (pan) 手势来配置此立方体,并将其绑定到 MouseLook.cs 脚本中。 此 widget 的功能与超极本触摸板的功能相似。

我将这些 GUI widget 放在主摄像头视图之外,并将它们的层设置为 GUIWidget。 图 1 展示了运行时的场景,其中使用了 GUI widget 发射球形弹并控制 FPC 的位置。


图 1. 带有地形并发射了球形弹的 FPC 场景

场景中,球形弹从 FPC 发射出,穿过树木。 为了补救,我需要为每棵树配置一个 mesh 或盒式对撞机。 这种场景的另一个问题是,如果我使用触摸板让 FPC 向下看并按环形手指将 FPC 向前移动时,前行速度将变慢。 为了解决这一问题,我限制了按下“向前移动”按钮时的“向下看”角度。

多次点触

基本场景包括 FPC 以指定角度从中心向外投弹。 默认从中心向外发射的角度是当俯视 FPC 时顺时针 30 度。

我为场景配置了多次点触,其能够在少于指定时间微分内启动,改变球形弹发射的角度,然后发射球形弹。 我可以通过控制左拇指跳跃脚本中的浮点变量配置该行为,使其根据序列中点击数量(number of tap)的增加来快速扩大角度。 这些浮点变量可以控制发射角度,并追踪自上一颗球形弹发射后的时间:

	private float timeSinceFire = 0.0f;
	private float firingAngle = 30.0f;

然后,我在左拇指跳跃脚本中配置了 Update 循环来减少跳跃范围手势少于 1/2 秒间隔时的发射角度。 如果点触间隔大于 1/2 秒,或发射角度已经减少到 0 度,则发射角度将重置为 30 度。 代码如下:

		timeSinceFire += Time.deltaTime;

			if(timeSinceFire <= 0.5f)
			{
				firingAngle += -1.0f;

			}
			else
			{
				firingAngle = 30.0f;
			}

			timeSinceFire = 0.0f;

			if(firingAngle <= 0)
			{
				firingAngle = 30;
			}


			projectileSpawnRotation = Quaternion.AngleAxis(firingAngle,CH.transform.up);

该代码还可制作扫射效果,连续点击可发射球形弹并同时缩减其发射角度(见图 2)。 该效果允许用户定制或在仿真或游戏中的特定状况下使用。


图 2.连续点击可旋转已发射球形弹的方向。

缩放与拖拽

我在图 1 的右下角配置了方块,其作用相当于键盘上的触摸板。 在方块上进行拖拽操作不会移动方块,而会通过传送 FPS 的 MouseLook 脚本向上、下、左和右旋转情景的主摄像头。 同样,方块接收到的缩放手势(与其他平台上的缩放功能类似)不会缩放方块,只会改变主摄像头的视场 (FOV),支持用户缩放主摄像头当前捕获的画面(参见图 3)。 我将配置一个拖拽手势,该手势可在缩放手势将 FOV 返回默认的 60 度后不久启动。

我通过设置 Boolean 变量 — 拖拽 — 以及浮点变量来控制上次缩放手势操作至今的时间:

	private float timeSinceScale;
	private float timeSincePan;
	private bool panned;

我将缩放手势启动时的 timeSinceScale 变量设置为 0.0f,并将拖拽手势启动时的拖拽变量设置为“真”。 场景主摄像头的 FOV 在 Update 循环中按照如下方式在触摸板正方体中添加的脚本中进行调整:

		timeSinceScale += Time.deltaTime;
		timeSincePan += Time.deltaTime;

		if(panned && timeSinceScale >= 0.5f && timeSincePan >= 0.5f)
		{
			fieldOfView += 5.0f;
			panned = false;
		}

		if(panned && timeSinceScale <= 0.5f)
		{
			fieldOfView = 60.0f;
			panned = false;
		}

		Camera.main.fieldOfView = fieldOfView;

以下是 onScale 和 onPan 函数。 请注意 timeSincePan 浮点变量,该变量可在触摸板用于摄像头时阻止 FOV 持续增加:

	private void onPanStateChanged(object sender, GestureStateChangeEventArgs e)
    {
        switch (e.State)
        {
            case Gesture.GestureState.Began:
            case Gesture.GestureState.Changed:
                var target = sender as PanGesture;
                Debug.DrawRay(transform.position, target.WorldTransformPlane.normal);
                Debug.DrawRay(transform.position, target.WorldDeltaPosition.normalized);

                var local = new Vector3(transform.InverseTransformDirection(target.WorldDeltaPosition).x, transform.InverseTransformDirection(target.WorldDeltaPosition).y, 0);
                targetPan += transform.InverseTransformDirection(transform.TransformDirection(local));

                //if (transform.InverseTransformDirection(transform.parent.TransformDirection(targetPan - startPos)).y < 0) targetPan = startPos;
                timeSincePan = 0.0f;
				panned = true;
				break;

        }

    }

	private void onScaleStateChanged(object sender, GestureStateChangeEventArgs e)
    {
        switch (e.State)
        {
            case Gesture.GestureState.Began:
            case Gesture.GestureState.Changed:
                var gesture = (ScaleGesture)sender;

                if (Math.Abs(gesture.LocalDeltaScale) > 0.01 )
                {
					fieldOfView *= gesture.LocalDeltaScale;

					if(fieldOfView >= 170){fieldOfView = 170;}
					if(fieldOfView <= 1){fieldOfView = 1;}

					timeSinceScale = 0.0f;


                }
                break;
        }
    }


图 3. 场景的主摄像头通过适当的 GUI 触摸板模拟器“放大”远距离的特征

按下并释放,然后快速翻看

当左侧的小范围接收到按下并释放的手势,然后在 1/2 秒内使用 Flick Gesture (快速翻看手势)时,以下手势序列将会提高 FPC 的水平速度。

为了添加该功能,首先,我添加了一个浮点变量来追踪范围接收到 Release Gesture (释放手势)后的时间,并添加了一个 Boolean 变量来追踪范围接收 Flicked Gesture(快速翻看手势)的情况:

	private float timeSinceRelease;
	private bool flicked;

作为场景的初始设置,我在左侧小范围脚本中添加了访问 FPC InputController 的脚本,以允许左侧小范围能够调用将 FPC 移动到左侧的操作。 控制 FPC 横向速度的变量不是位于 InputController,而是位于 FPC 的 CharacterMotor。 允许将左侧小范围的脚本加入 CharacterMotor 的配置如下:

		CH = GameObject.Find("First Person Controller");
		CHFPSInputController = (FPSInputController)CH.GetComponent("FPSInputController");
		CHCharacterMotor = (CharacterMotor)CH.GetComponent ("CharacterMotor");

脚本的 onFlick 函数仅可将快速翻看的 Boolean 变量设置为 True。

脚本的 Update 函数(每帧调用一次)可按照如下方式改变 FPC 的横向运动速度:

		if(flicked && timeSinceRelease <= 0.5f)
		{
			CHCharacterMotor.movement.maxSidewaysSpeed += 2.0f;
			flicked = false;
		}

		timeSinceRelease += Time.deltaTime;
	}

该代码可支持用户通过按下并释放左侧小范围,然后在 1/2 秒内快速翻看左侧小范围来提高 FPC 的横向运动速度。 您可以通过任意方式配置降低横向速度的能力,包括按下并释放左侧索引范围,然后使用 Flick Gesture(快速翻看手势)。 请注意,CHCharacterMotor.movement 方法不仅包括 maxSidewaysSpeed,还包括重力、maxForwardsSpeed、maxBackwardsSpeed 和其他参数。 接收它们并于这些参数一起使用的许多 TouchScript 手势和几何可为开发 Unity 3D 场景的触摸界面提供许多选项和策略。 当为这些类型的应用开发触摸界面时,尝试将众多选项缩减为可提供最有效且最符合人体工程学的用户体验的少数选项。

手势序列的问题

我在本文的示例中配置的手势序列大量使用了 Time.deltaTime 函数。 我将该微分与确定某个操作的微分之前和之后的手势结合使用。 我在配置这些示例时遇到的两个主要问题是:时间微分的大小和使用的手势。

时间微分

我在本文中使用的时间微分是 1/2 秒。 当我使用 1/10 秒这一更短的时间时,手势序列无法识别。 虽然我感觉点触的速度足以让手势序列识别出,但是预期的场景操作并未出现。 这可能是硬件和软件延迟的结果。 因此,当开发手势序列时,应记住目标硬件平台的性能特征。

手势

在配置该示例时,最初我准备加入缩放和拖拽手势,然后加入点触和快速翻看手势。 确保缩放和拖拽手势按照预期使用后,我加入了点触手势,这可以让缩放和拖拽手势停止使用。 虽然我可以在拖拽手势之后配置一个缩放序列,但是这种手势序列不符合用户使用习惯。 最有效的序列应在 widget 中包含另一个几何目标,在缩放和拖拽手势后接收点触和快速翻看手势。

我在本示例中使用了 1/2 秒的时间微分作为操作使用(或不使用)的断点。 虽然它为用户界面 (UI) 增加了一定的复杂性,您可以配置该示例使用多个时间微分。 使用按下并释放手势,然后在 1/2 秒内使用快速翻看手势可以导致水平速度增加;使用按下并释放手势,然后再 1/2 秒至 1 秒之间使用快速翻看手势可以降低水平速度。 以这种方式使用时间微分不仅能够为 UI 提供灵活性,还可用于在场景内部安置“复活节彩蛋”。

结论

我为本文配置的手势序列场景在运行 Windows 8 的超极本设备上使用了采用 TouchScript 的 Unity 3D。 实施的序列旨在减少用户与应用交互所需的触目屏幕面积。 用于用户交互的屏幕界面的面积越少,能够用于视觉内容的面积越多。

当我无法获得一个手势序列按照预期的方式执行时,我能够构建一个可行的替代方案。 此性能调优的一部分是调整 Time.deltaTime 微分,从而获取一个手势序列按照预期在可用的硬件上执行。 同样地,我在本文中构建的 Unity 3D 场景显示,在超极本设备上运行的 Windows 8 能够用于开发使用手势序列的应用。

相关内容

关于作者

Lynn Thompson 是一位 IT 专业人员,在商业和工业计算环境领域拥有二十多年的经验。 最初,他曾在一家电力公司的控制系统更新项目中,使用 CAD 修改并创建控制系统图。 在此期间,Lynn 获得了内布拉斯加大学林肯校区(University of Nebraska, Lincoln)电气工程专业的理学士学位。 在互联网繁荣时期,他继续在一家 IT 整合企业担任系统管理员。 这份工作主要处理多种平台上的操作系统、数据库和应用管理。 在互联网泡沫破灭之后,他为服装、石油和天然气以及国防领域的企业的多种项目提供 IT 咨询服务。 现在,Lynn 又回到原点,担任电力公司的工程师。 后来,Lynn 获得内布拉斯加大学林肯校区 (University of Nebraska, Lincoln) 工程管理专业的工程硕士学位。

 

英特尔、Intel 标识、超极本和 VTune 是英特尔公司在美国和其他国家的商标。
*其他的名称和品牌是其他所有者的资产。
版权所有© 2014 年英特尔公司。 所有权保留。

Legend of Xuan Yuan Case Study: Get the best gameplay with 2 in 1 state, touch, and accelerometer

$
0
0

Download PDF

Abstract

Tencent wanted to give gamers the best experience on Intel® Ultrabook™ and 2 in 1 systems. Legend of Xuan Yuan was already a successful game, but these systems provided Tencent with a new opportunity. Many systems currently provide 2 in 1 usage, meaning they can be handled as a traditional laptop or a tablet. Tencent worked with Intel engineers to detect the laptop and tablet modes to change the game’s state. They updated the UI to support touch, which has become one of the most essential and exciting features on tablets. Finally, the system’s sensors allowed new gameplay by including “shake” to enable a special action in the game.

Introducing the first touch 3D MMOPRG for the Chinese market

Tencent is the biggest game developer in China. With a growing number of 2 in 1 systems in the Chinese market, Tencent wanted to give their players a unique experience. After two years in the market, Legend of Xuan Yuan was already a popular title. The availability of Ultrabooks and 2 in 1 systems made it the right time to add touch and accelerometer support to the game.  Although 3D MMORPGs are very popular in China, none of them supported touch before Legend of Xuan Yuan. Tencent had a chance to innovate, but there was also risk – would the changes be successful? This case study illustrates how, working with Intel engineers, Tencent changed the game to play well on 2 in 1 systems and Ultrabooks running Windows* 8.

Legend of Xuan Yuan needs two different UIs for tablet and laptop modes. On 2 in 1 systems, the game detects when the system is used as a laptop versus a tablet. The game uses keyboard and mouse when the system is in laptop mode. When it’s used as a tablet, the game switches to a touch-only UI. Tencent wanted an effortless transition between the traditional laptop mode and touch gameplay. The player has a seamless experience because the UI changes automatically to suit each mode. In this case study, we’ll look at how to detect the mode of a 2 in 1 system and change the UI based on that mode.

Converting an existing user interface to touch can be difficult. It’s especially hard for games with rich UIs that rely on left-click, right-click, and multiple command keys. There’s no single formula for adapting this kind of UI. It requires great care to deliver smooth and satisfying gameplay via touch. Because the game had an existing installed base, the team was careful to make the smallest changes possible and not alienate existing players. We’ll review the UI design.

Since these systems include an accelerometer, Tencent also added support for a “super-kill” attack against opponents when you shake the system during gameplay.

Changing game mode to match the 2 in 1 state

Legend of Xuan Yuan has two UI personalities and dynamically changes the UI based on the state of a 2 in 1 system. When the system is in laptop mode, Legend of Xuan Yuan plays as it always has with keyboard and mouse input. When the system is in tablet mode, the player uses touch input. How does this work?

Here’s how we did it: Detecting 2 in 1 state changes and changing UI mode

Legend of Xuan Yuan listens for the WM_SETTINGCHANGE message. This message notifies apps when the system changes state. The WM_SETTINGCHANGE message comes with its LPARAM pointing to a string with a value of “ConvertibleSlateMode” when the 2 in 1 state changes. A call to GetSystemMetrics(SM_CONVERTIBLESLATEMODE) reveals the current state.

When the game is in tablet mode, it displays an overlay UI with touch buttons for the various UI actions. It hides the overlay UI in laptop mode.

Legend of Xuan Yuan uses detection code like this:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  case WM_SETTINGCHANGE:
    if (lParam != NULL && wcscmp(TEXT("ConvertibleSlateMode"), (TCHAR *)lParam) == 0)
    {
      BOOL bSlateMode = (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0);
      if (bSlateMode == True) //Slate mode, display the Touch overlay UI
        …
      else //Laptop mode, hide the touch overlay UI
        …
    }

Figure 1: Code to detect system setting change and check system mode

For more details, check the basic 2 in 1 aware sample.

This technique must be enabled by the system OEM, with a supporting driver installed, in order to work. In case it’s not properly enabled on some systems, we included a manual way to change the UI configuration. A later section describes how the UI works.

Now it’s your turn: Detect if the system is used as a laptop or tablet

How can you detect the system state for your game and how should it change its UI? To play best on 2 in 1 systems, your game should have dual personalities and dynamically change its UI based on the state of the system.

First plan a UI for both laptop and tablet modes. Consider how the system might be held or placed. Pick the UI interactions that work best for your players. As you design the touch interface, you should reserve more screen area for your touch controls than you typically need for mouse buttons. Otherwise, players will struggle to reliably press the touch controls.

Touch interactions are often slower than keyboard and mouse, so keep that in mind too. Game menus also need both a keyboard plus mouse UI and a touch UI.

It’s a good idea to check the system state at startup with GetSystemMetrics and set your UI accordingly. Remember that not all systems will correctly report their state or notify your game of state changes, so choose a default startup state for your game’s UI in case the state isn’t detected.

Listen for the WM_SETTINGCHANGE message once the game is running. When the message arrives, check its contents for an LPARAM pointing to a string with a value of “ConvertibleSlateMode”. That value indicates that the game should call GetSystemMetrics(SM_CONVERTIBLESLATEMODE) and check if the UI should change.

Detection may not be conclusive because all systems may not correctly report state changes. Your game should probably default to laptop mode if the detection doesn’t give certain results. It should definitely include a way to manually change the UI between keyboard/mouse mode and tablet mode.

For a complete sample that detects system state and changes its UI, look at the 2 in 1 aware sample. To see a more complex sample that detects docking, screen orientation, and more, check the detecting state sample.

Deciding on a touch message type

You’ll need to decide which Window message type to support before you can add touch support to an existing application. Choose one of the three different sets of Window messages: WM_POINTER, WM_GESTURE, or WM_TOUCH. We’ll walk through the decision process used for Legend of Xuan Yuan and examine ways you can do the same for your game.

How we did it: Comparing touch message types

Touch support is at the center of the new version of Legend of Xuan Yuan. When players use the touch screen, they see a new UI with a set of touch controls on screen.

WM_POINTER is the easiest message type to code, and it supports a rich set of gestures. WM_POINTER only runs on Windows 8 and beyond. Tencent wanted to support a large installed base of Windows 7 players, so WM_POINTER was not the right choice.

Before we discuss the remaining message types, let’s review the key UI elements for Legend of Xuan Yuan. The game’s touch UI uses on-screen button controls. These controls can be used for movement and actions at the same time. The movement and action controls are on opposite sides of the screen, for use with two hands. These controls are in the bottom corners of the screen. There’s also an icon near the top of the screen to bring up a cascading menu for more complex UI elements. We’ll discuss the design of the UI later, but this gives us a good idea how the UI elements must work.


Figure 2: On-screen touch overlay UI, in left and right bottom corners

The game must recognize simultaneous points of contact from different parts of the screen. Because multiple touches must work at the same time, we refer to this as multi-touch.

Now that we understand the main parts of the multi-touch UI, we can compare the remaining touch message types: WM_GESTURE and WM_TOUCH. The easiest one to code is WM_GESTURE, which has simple support for typical gestures like a two-finger pinch (zoom) and finger swipe (pan). This message type hides some of the detail of touch interaction and presents your code with a complete gesture once the gesture is done. Simple touch events are still sent to your game as mouse messages. This means a typical touch interface could be implemented using mouse messages for simple touch events plus WM_GESTURE for complex gestures.

The gestures supported by WM_GESTURE can only include one set of related touch points. This makes it difficult to support gestures from this kind of multi-touch UI where the player touches the screen in different places. WM_GESTURE is a poor choice for this game.

WM_TOUCH is the lowest-level touch message type. It gives complete access to all touch events (e.g., “finger down”). WM_TOUCH requires you to do more work than the other message types since you must write code to represent all high-level touch events and gestures out of low-level touch messages. In spite of the extra work required, WM_TOUCH was the clear choice for Legend of Xuan Yuan. WM_TOUCH gave complete control over all touch interaction including multi-touch.

When there’s a physical touch on the screen, the system sends WM_TOUCH messages to the game. The game also receives a mouse click message at the same time. This makes it possible for apps without full touch support to behave properly with touch. Because these two messages of different types describe the same physical event, this can complicate the message handling code. Legend of Xuan Yuan uses mouse-click messages where possible and discards duplicate messages.

Your turn: Choosing the right touch message type for your game

WM_POINTER is a great option if your game will only be used on Windows 8. If you need backward compatibility, look at both WM_GESTURE and WM_TOUCH messages.

Consider your UI design as you compare the message types. If your UI relies heavily on gestures, and you can easily write mouse-click handlers for the non-gesture single touch events, then WM_GESTURE is probably right for your game. Otherwise, use WM_TOUCH. Most games with a full-featured UI use WM_TOUCH, especially when they have multiple controls that players will touch at the same time.

When you evaluate the touch messages, don’t forget the menu system. Remember also to discard extra messages that arrive as mouse clicks.

To learn more about the tradeoffs between the three message types, see this article. For more detail on choosing between the backwards-compatible WM_TOUCH and WM_GESTURE message types, see https://software.intel.com/en-us/articles/touch-samples.

Adapting the UI to use touch

Adapting an existing game UI to touch can be complex, and there’s no single formula for how to do it well.

How we did it: A new touch UI

The keyboard and mouse UI is familiar. It uses the W, A, S, D keys to move the character. Customizable action keys on the bottom of the screen and shortcut keys 1-9 hold potions, attack skills, and open richer UI elements. These UI elements include inventory, skill tree, task, and map. Right-click selects the character’s weapon and armor or opens a treasure box.

The touch screen is available at all times, but the touch UI is hidden by default during keyboard and mouse gameplay. A touch button is visible on-screen in this mode.


Figure 3: Pressing this touch button in this mode brings up the touch UI

If the player switches the system to tablet mode or touches this button, the full touch UI appears on-screen.

How we did it: Elements of the touch UI

In tablet mode, the player usually holds the system with both hands. The UI layout uses both thumbs to minimize any grip changes. Move and attack actions are grouped for easy access by the player’s left and right thumbs.

First, we designed a wheel control to move the character. The wheel is an overlay on the left side of the screen. This is similar to game controllers, and this familiar use and placement makes it easy to use. The player’s left thumb will usually be in constant contact with the screen. As they slide their thumb around, the character moves on-screen in the direction of the player’s thumb.

The regular in-game action bar is at the bottom of the screen, but that doesn’t work well for thumb use. We added a group of 4 large action buttons in the bottom right corner where the player’s right thumb can easily reach them. The player can configure these to trigger their most frequently-used actions by dragging attack skills or potions to each button.

The player must target an enemy before attacking. With the keyboard/mouse interface, left-click targets a single enemy and TAB targets the next enemy within attack range. In touch mode there’s a large button to target the next close enemy. The player can also touch an enemy to target them directly, but that’s not common since it disrupts the player’s grip on the tablet.

The keyboard and mouse UI uses right-click to open a treasure box, equip a weapon or armor, or drink potions. Tap and hold is the best touch replacement for right-click, so it replaces right-click for the touch UI.

With the keyboard/mouse UI, there’s a small icon on-screen to open the cascaded windows. This doesn’t work well for touch since the icons are too small. The touch UI includes an icon on-screen to bring up the rest of the UI elements through a cascading set of icons. These icons bring up more complex parts of the UI like the inventory bag, skill tree, tasks, etc. There is also an option to toggle the UI between the keyboard/mouse and the touch overlay. This gives the player an easy way to change between the two UIs.


Figure 4: Full touch UI with movement wheel, action and target buttons, and the cascading UI displayed

Here’s the full touch UI with the cascading icons open.

How we did it: Message handling for the touch UI

How does the message handling work? It varies for different parts of the UI. Both WM_TOUCH and mouse messages are used. The action, targeting, and cascading UI buttons all use mouse click messages. The movement wheel and main part of the game screen use WM_TOUCH messages.

Typical gameplay involves continuous touching on the movement wheel control, with repeated use of the enemy selection and skill attack buttons. This means that good multi-touch support is essential. Luckily, WM_TOUCH has good support for multi-touch.

When there’s a WM_TOUCH message, the game saves some context. It compares this touch with other recent WM_TOUCH messages, checks how long the current sequence of touches has been held, and looks for the location of the touch.

If the WM_TOUCH message was on or near the movement wheel, the code checks the location of the touch relative to the center of the wheel and the previous touch. If the touch was close to a previous touch and this current gesture started on the wheel, the game moves the character in the desired direction. During development, this required some careful configuration to detect the difference between long continuous touches on the movement wheel and other touches on the main part of the screen.

If a WM_TOUCH message is on the screen away from the other controls, then it might be part of a gesture like zoom or pan, or it may be part of a tap-and-hold. WM_TOUCH messages are compared with previous ones to decide which action to take. If it’s close enough to the first and has been held for longer than 0.2 seconds, it’s treated as a tap-and-hold. Otherwise, it’s a gesture so the screen is adjusted to match.

The system also automatically generates mouse messages for all touch messages. Each mouse message includes extra information detailing where it came from. The GetMessageExtraInfo call identifies the difference.

#define MOUSEEVENTF_FROMTOUCH 0xFF515700

if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) {
  // Click was generated by wisptis / Windows Touch
}else{
  // Click was generated by the mouse.
}

Figure 5: Check if mouse messages came from touch screen

When a mouse message was generated from the touch screen and the game has already handled the physical touch via WM_TOUCH, the game discards the mouse message.

If a touch message is on one of the other controls, then it is discarded and the mouse message is used instead.

With all UI elements in place, the game plays well with a touch screen.

This article shows another example of adapting a complex UI to touch in Wargame: European Escalation: https://software.intel.com/en-us/articles/wargame-european-escalation-performance-and-touch-case-study

Your turn: Building your touch UI

Before you build a touch UI for your game, imagine all the actions a player might take. Then think about how they might be done with touch (or other sensors like the accelerometer). Pay special attention to the differences between tap and click, continuous actions like press-and-hold, and gestures like drag.

Decide how the player will do all of these actions with touch and where the visible controls should be. For any on-screen controls or cascading menus, ensure they are big enough to use with a fingertip or thumb. Think about how your typical player will hold the system, and design your UI for easy touch access with a typical grip.

Now that you have the UI planned, use the simplest message for the job. Identify when a touch hits each control. Plan which message type to use for those controls (mouse or touch) and discard duplicate messages.

For touch messages, save the context of the touch message. Location, control, and timing will all be useful when you need to compose gestures out of multiple touch messages. Think about the parts of your gameplay that require continuous touch contact. Carefully test this during development to make sure that your game works well with typical variations in gestures. Check a variety of gesture directions, touch locations, proximity to previous touches, and touch durations.

Start the UI in whatever mode matches the system’s current state. Switch the UI between touch and keyboard/mouse whenever the system state changes. Finally, remember to include a manual way to force the UI change in case the system isn’t configured to notify you properly.

For more tips on designing your touch UI, see the Ultrabook and tablet Windows touch developer guide.

Sensors

Ultrabook and 2 in 1 systems include sensors like gyroscope, accelerometer, GPS, etc. It’s possible to enhance the gameplay experience with them.

How we did it: Shake for a special action

Legend of Xuan Yuan uses the accelerometer to detect when the player shakes the system. The player accumulates energy during gameplay, then releases it during a super kill attack. The player can shake the system to trigger the super kill, which attacks nearby enemies for 10-20 seconds.

We tested some different shake actions to measure typical values from the accelerometer:


Figure 6: Four shake actions, showing intensity and duration in 3 dimensions

Any acceleration over 1.6 on one axis is a shake. We could also use the sum of the absolute values of acceleration on each axis.

Because these are real-world events, the data will be noisy and different each time. The values include both long and short shakes. While most of our test shakes gave a single peak value, one of them had several near-peak values. This game uses any shake over 1.6 in any direction on any axis. Multiple shakes within 1.5 seconds are grouped together as one.

With this code in the game, any shake action will unleash a super kill action.

Your turn: Use the system’s sensors

Ultrabook and 2 in 1 systems contain a number of sensors. Be creative, and think of ways you might use each of them to enhance your gameplay.

Whichever sensor(s) you use, calibrate them to see how they react in real-world conditions. Consider the different typical conditions your players will encounter.

Summary

We’ve shown how to adapt an existing game to detect the state (laptop or tablet) of a 2 in 1 system. We also demonstrated how the UI can support touch and how to switch between UIs based on the 2 in 1 system state. Along with the accelerometer to trigger a unique action in the game, these give a compelling game experience.

Tencent took a risk by introducing the first Chinese MMORPG to support touch gameplay. The risk has paid off! Legend of Xuan Yuan plays great on laptops, tablets, and 2 in 1 systems. We hope you have similar success with your game!

Authors

Mack Han is a game client software engineer for Tencent with 10 years of game development experience. He has built games for console, PC, and mobile. He has been working with a big 3D MMORPG for years, specializing in rendering and optimizing.

Cage Lu is an Application Engineer at Intel. He has been working with big gaming ISVs in China for several years to help them optimize game client performance and user experience on Intel® platforms.

Paul Lindberg is a Senior Software Engineer in Developer Relations at Intel. He helps game developers all over the world to ship kick-ass games and other apps that shine on Intel platforms.

References

Detecting tablet and laptop mode and screen orientation in a 2 in 1 system: http://software.intel.com/en-us/articles/detecting-slateclamshell-mode-screen-orientation-in-convertible-pc

More details about adapting to 2 in 1 systems:
http://software.intel.com/en-us/articles/how-to-write-a-2 in 1aware-application

Comparing the various Windows 8 touch message types:
http://software.intel.com/en-us/articles/comparing-touch-coding-techniques-windows-8-desktop-touch-sample

Case study showing touch implementation for Wargame: European Escalation:
http://software.intel.com/en-us/articles/wargame-european-escalation-performance-and-touch-case-study

Touch developer guide:
http://software.intel.com/en-us/articles/ultrabook-device-and-tablet-windows-touch-developer-guide

A more complex touch use case:
http://software.intel.com/en-us/articles/hot-shots-warps-conventional-touch-gaming

License

Intel sample source is provided under the Intel Sample Source License Agreement.  Portions of this document are subject to the Microsoft Limited Public License.

 

Intel®Developer Zone offers tools and how-to information for cross-platform app development, platform and technology information, code samples, and peer expertise to help developers innovate and succeed.  Join our communities for the Internet of Things, Android*, Intel® RealSense™ Technology and Windows* to download tools, access dev kits, share ideas with like-minded developers, and participate in hackathons, contests, roadshows, and local events.

 

Intel, the Intel logo, and Ultrabook are trademarks of Intel Corporation in the U.S. and/or other countries.
Copyright © 2014 Intel Corporation. All rights reserved.
*Other names and brands may be claimed as the property of others.

 

使用 MonoGame* 开发游戏

$
0
0

作者:Bruno Sonnino

Download article as PDF

全球各地的开发人员都希望开发游戏。 为什么不呢? 游戏是计算机历史上销量最高的产品之一,游戏业务带来的财富不断吸引着开发人员的加入。 作为开发人员,我当然希望成为下一个开发愤怒的小鸟* 或光晕*的开发人员。

但是,事实上,游戏开发是软件开发最困难的领域之一。 你不得不牢记那些从来不会使用的三角函数、几何和物理类。 除此之外,你的游戏必须以吸引用户沉浸其中的方式来组合声音、视频和故事情节。 然后,你需要再编写一行代码!

为了简化难度,开发游戏使用的框架不仅要能够使用 C 和 C++,还要能够使用 C# 或 JavaScript*(是的,你可以使用 HTML5 和 JavaScript 开发适用于您的浏览器的三维游戏)。

其中一个框架是 Microsoft XNA*,该框架基于 Microsoft DirectX* 技术,支持为 Xbox 360*、Windows* 和 Windows Phone* 创建游戏。 微软已经初步淘汰了 XNA,但是与此同时,开源社区加入了一位新成员: MonoGame*。

MonoGame 是什么?

MonoGame 是 XNA 应用编程接口(API)的开源实施方式。 它不仅能够实施面向 Windows 的 XNA API,还能够实施面向 Mac* OS X*、Apple iOS*、Google Android*、Linux* 和 Windows Phone 的 XNA API。 这意味着,你只需进行较少的改动即可为所有平台开发游戏。 这种特性非常棒:你可以使用能够轻松移植至所有主要台式机、平板电脑和智能手机平台的 C# 来创建游戏。 该框架能够帮助开发人员开发出一款享誉全球的游戏。

在 Windows 上安装 MonoGame

甚至,你不需要使用 Windows 便可使用 MonoGame 进行开发。 你可以使用 MonoDevelop* (面向 Microsoft .NET 语言的开源跨平台集成开发环境 [IDE])或 Xamarin 开发的一款跨平台 IDE — Xamarin Studio*。 借助这些 IDE,你可以使用 C# 在 Linux 或 Mac 上进行开发。

如果你是一位 Microsoft .NET 开发人员,并且日常使用的工具是 Microsoft Visual Studio*,你可以像我一样将 MonoGame 安装到 Visual Studio 中并且用它来创建游戏。 在撰写本文时,MonoGame 的最新稳定版本是 3.2 版。该版本可在 Visual Studio 2012 和 2013 中运行,并支持创建支持触摸功能的 DirectX 桌面游戏。

MonoGame 安装在 Visual Studio 中随附了许多新模板,你可从中选择来创建游戏,如图 1 所示。

图 1.全新 MonoGame* 模板

现在,如要创建第一个游戏,请点击 MonoGame Windows Project,然后选择一个名称。 Visual Studio 可创建一个包括所有所需文件和参考的新项目。 如果运行该项目,则应如图 2 所示。

图 2.在 MonoGame* 模板中创建的游戏

很无聊,是吗? 只有一个蓝色屏幕;但是,构建任何游戏都要从它开始。 按 Esc,则可关闭窗口。

现在,你可以使用目前拥有的项目开始编写游戏,但是有一个问题: 如要添加任何资产(图像、子图、声音或字体),你需要将其编写为与 MonoGame 兼容的格式。 对于这一点,你需要以下选项之一:

  • 安装 XNA 游戏 Studio 4.0
  • 安装 Windows Phone 8 软件开发套件(SDK)
  • 使用外部程序,如 XNA 内容编译器

XNA Game Studio

XNA Game Studio 可提供为 Windows 和 Xbox 360 创建 XNA 游戏所需的一切组件。 此外,它还包括内容编译器,可将资产编译至 .xnb 文件,然后编译 MonoGame 项目所需的一切文件。 目前,仅可在 Visual Studio 2010 中安装编译器。 如果你不希望仅出于该原因来安装 Visual Studio 2010,则可在 Visual Studio 2012 中安装 XNA Game Studio(详见本文“了解更多信息”部分的链接)。

Windows Phone 8 SDK

你可以在 Visual Studio 2012 中直接安装 XNA Game Studio,但是在 Visual Studio 2012 中安装 Windows Phone 8 SDK 更好。 你可以用它创建项目来编译资产。

XNA 内容编译器

如果不希望安装 SDK 来编译资产,则可使用 XNA 内容编译器(详见“了解更多信息”中的链接),该编译器是一款开源程序,能够将资产编译至 MonoGame 中可使用的 .xnb 文件。

创建第一个游戏

使用 MonoGame 模板创建的上一个游戏可作为所有游戏的起点。 你可以使用相同的流程创建所有游戏。 Program.cs 中包括 Main 函数。 该函数可初始化和运行游戏:

static void Main()
{
    using (var game = new Game1())
        game.Run();
}

Game1.cs是游戏的核心。 有两种方法需要在一个循环中每秒钟调用 60 次: 更新和绘制。 在更新中,为游戏中的所有元素重新计算数据;在绘制中,绘制这些元素。 请注意,这是一个紧凑的循环。 你只有 1/60 秒,也就是 16.7 毫秒来计算和绘制数据。 如果你超出该事件,程序就会跳过一些绘制循环,游戏中就会出现图形故障。

近来,台式电脑上的游戏输入方式是键盘和鼠标。 除非用户购买了外部硬件,如驱动轮和操纵杆,否则我们只能假定没有其他的输入方法。 随着新硬件的推出,如超极本™ 设备、 2 合 1 超极本和一体机, 输入选项发生了变化。 你可以使用触摸输入和传感器,为用户提供更加沉浸式、逼真的游戏体验。

对于第一款游戏,我们将创建足球点球赛。 用户使用触摸的方式来“射门”,计算机守门员接球。 球的方向和速度由用户的敲击动作来决定。 计算机守门员将会随机选择一个方向和速度接球。 射门成功得一分。 反之,守门员的一分。

向游戏添加内容

游戏中的第一步是添加内容。 通过添加背景场地和足球开始。 如要执行该操作,则需要创建两个 .png 文件:一个文件用于足球场(图 3),另一个用于足球(图 4)。

 

图 3.足球场

 

 

图 4.足球

如要在游戏中使用这些文件,你需要对其进行编译。 如果正在使用 XNA Game Studio 或 Windows Phone 8 SDK,则需要创建一个 XNA 内容项目。 该项目不需要在同一个解决方案中。 你只需要用它来编译资产。 将图像添加至该项目并对其进行构建。 然后,访问项目目标目录,并将生成的 .xnb 文件复制至你的项目。

我更喜欢使用 XNA 内容编译器,它不需要新项目且支持按需编译资产。 仅需打开程序,将文件添加至列表,选择输出目录,并点击“编译(Compile)”。 .xnb 文件便可添加至该项目。

内容文件

.xnb 文件可用时,将其添加至游戏的 “内容( Content)” 文件夹下。 你必须为每个文件,包括“内容(Content)”“复制至输入目录(Copy to Output Directory)”以及“如果较新则复制(Copy if Newer)”,设置构建操作。 如果不执行该操作,则会在加载资产时出现错误。

创建两个字段存储足球和足球场的纹理:

private Texture2D _backgroundTexture;
private Texture2D _ballTexture;

这些字段可在 LoadContent 方法中加载:

protected override void LoadContent()
{
    // Create a new SpriteBatch, which can be used to draw textures.
    _spriteBatch = new SpriteBatch(GraphicsDevice);

    // TODO: use this.Content to load your game content here
    _backgroundTexture = Content.Load<Texture2D>("SoccerField");
    _ballTexture = Content.Load<Texture2D>("SoccerBall");
}

请注意,纹理的名称与内容(Content )文件夹中的文件名称相同,但是没有扩展名。

接下来,在 Draw 方法中绘制纹理:

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.Green);

    // Set the position for the background
    var screenWidth = Window.ClientBounds.Width;
    var screenHeight = Window.ClientBounds.Height;
    var rectangle = new Rectangle(0, 0, screenWidth, screenHeight);
    // Begin a sprite batch
    _spriteBatch.Begin();
    // Draw the background
    _spriteBatch.Draw(_backgroundTexture, rectangle, Color.White);
    // Draw the ball
    var initialBallPositionX = screenWidth / 2;
    var ínitialBallPositionY = (int)(screenHeight * 0.8);
    var ballDimension = (screenWidth > screenHeight) ?
        (int)(screenWidth * 0.02) :
        (int)(screenHeight * 0.035);
    var ballRectangle = new Rectangle(initialBallPositionX, ínitialBallPositionY,
        ballDimension, ballDimension);
    _spriteBatch.Draw(_ballTexture, ballRectangle, Color.White);
    // End the sprite batch
    _spriteBatch.End();
    base.Draw(gameTime);
}

这种方法是用绿色清屏,然后绘制背景并绘制罚球点的足球。 第一种方法 spriteBatch Draw可绘制能够调整为窗口尺寸的背景,位置 0,0;第二种方法可绘制罚球点的足球。 它可调整为窗口大小的比例。 此处没有运动,因为位置不改变。 接下来是移动足球。

移动足球

如要移动足球,我们必须重新计算循环中每个迭代的位置,并在新的位置绘制它。 在 Update方法中执行新位置的计算:

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
        Keyboard.GetState().IsKeyDown(Keys.Escape))
        Exit();

    // TODO: Add your update logic here
    _ballPosition -= 3;
    _ballRectangle.Y = _ballPosition;
    base.Update(gameTime);

}

足球位置在每个循环中都会通过减去三个像素进行更新。 如果你希望让球移动地更快,则必须减去更多的像素。 变量 _screenWidth_screenHeight_backgroundRectangle_ballRectangle_ballPosition是私有字段,可在 ResetWindowSize方法中进行初始化:

private void ResetWindowSize()
{
    _screenWidth = Window.ClientBounds.Width;
    _screenHeight = Window.ClientBounds.Height;
    _backgroundRectangle = new Rectangle(0, 0, _screenWidth, _screenHeight);
    _initialBallPosition = new Vector2(_screenWidth / 2.0f, _screenHeight * 0.8f);
    var ballDimension = (_screenWidth > _screenHeight) ?
        (int)(_screenWidth * 0.02) :
        (int)(_screenHeight * 0.035);
    _ballPosition = (int)_initialBallPosition.Y;
    _ballRectangle = new Rectangle((int)_initialBallPosition.X, (int)_initialBallPosition.Y,
        ballDimension, ballDimension);
}

该方法可根据窗口的尺寸重置所有变量。 它可在 Initialize方法中调用:

protected override void Initialize()
{
    // TODO: Add your initialization logic here
    ResetWindowSize();
    Window.ClientSizeChanged += (s, e) => ResetWindowSize();
    base.Initialize();
}

这种方法在两个不同的位置调用:流程的开始以及每次窗口发生改变时。 Initialize可处理 ClientSizeChanged,因此当窗口尺寸发生改变时,与窗口尺寸相关的变量将进行重新评估,足球将重新摆放至罚球点。

如果运行程序,你将看到足球呈直线移动,直至字段结束时停止。 当足球到达目标时,你可以使用以下代码将足球复位:

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
        Keyboard.GetState().IsKeyDown(Keys.Escape))
        Exit();

    // TODO: Add your update logic here
    _ballPosition -= 3;
    if (_ballPosition < _goalLinePosition)
        _ballPosition = (int)_initialBallPosition.Y;

    _ballRectangle.Y = _ballPosition;
    base.Update(gameTime);

}

The _goalLinePosition variable is another field, initialized in the ResetWindowSize method:

_goalLinePosition = _screenHeight * 0.05;

你必须在 Draw方法中做出另一个改变:移除所有计算代码。

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.Green);

   var rectangle = new Rectangle(0, 0, _screenWidth, _screenHeight);
    // Begin a sprite batch
    _spriteBatch.Begin();
    // Draw the background
    _spriteBatch.Draw(_backgroundTexture, rectangle, Color.White);
    // Draw the ball

    _spriteBatch.Draw(_ballTexture, _ballRectangle, Color.White);
    // End the sprite batch
    _spriteBatch.End();
    base.Draw(gameTime);
}

该运动与目标呈垂直角度。 如果你希望足球呈一定的角度移动,则需要创建 _ballPositionX字段,并增加(向右移动)或减少(向左移动)它。 更好的方法是将 Vector2用于足球位置,如下:

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
        Keyboard.GetState().IsKeyDown(Keys.Escape))
        Exit();

    // TODO: Add your update logic here
    _ballPosition.X -= 0.5f;
    _ballPosition.Y -= 3;
    if (_ballPosition.Y < _goalLinePosition)
        _ballPosition = new Vector2(_initialBallPosition.X,_initialBallPosition.Y);
    _ballRectangle.X = (int)_ballPosition.X;
    _ballRectangle.Y = (int)_ballPosition.Y;
    base.Update(gameTime);

}

如果运行该程序,将会显示足球以一个角度运行(图 5)。 接下来是让球在用户点击它时运动。

图 5.带有足球移动的游戏

触摸和手势

在该游戏中,足球的运动必须以触摸轻拂开始。 该轻拂操作决定了足球的方向和速度。

在 MonoGame 中,你可以使用 TouchScreen类获得触摸输入。 你可以使用原始输入数据或 Gestures API。 原始输入数据更灵活,因为你可以按照希望的方式处理所有输入;Gestures API 可将该原始数据转换为过滤的手势,以便只接受你希望接收的手势输入。

虽然 Gestures API 更易于使用,但是有几种情况不能使用这种方法。 例如,如果你希望检测特殊手势,如 X 型手势或多手指手势,则需要使用原始数据。

对于该游戏,我们仅需要轻拂操作,Gestures API 支持该操作,所以我们使用它。 首先需要通过使用 TouchPanel 类指明希望使用的手势。 例如,代码:

TouchPanel.EnabledGestures = GestureType.Flick | GestureType.FreeDrag;

. . . 仅支持 MonoGame 检测并通知轻拂和拖动操作。 然后,在 Update方法中,你可以按照如下方式处理手势:

if (TouchPanel.IsGestureAvailable)
{
    // Read the next gesture
    GestureSample gesture = TouchPanel.ReadGesture();
    if (gesture.GestureType == GestureType.Flick)
    {…
    }
}

首先,确定是否有可用手势。 如果有,则可以调用 ReadGesture获取并处理它。

使用触摸对运动执行 Initiate 操作

首先,使用 Initialize 方法在游戏中启用轻拂手势:

protected override void Initialize()
{
    // TODO: Add your initialization logic here
    ResetWindowSize();
    Window.ClientSizeChanged += (s, e) => ResetWindowSize();
    TouchPanel.EnabledGestures = GestureType.Flick;
    base.Initialize();
}

此时,足球在游戏运行时将会一直运动。 使用私有字段 _isBallMoving可在足球移动时通知游戏。 在 Update 方法中,当程序检测轻拂操作时,你将 _isBallMoving设置为 True,则足球将开始运动。 当足球到达球门线时,将 _isBallMoving设置为 False 并重置足球的位置:

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
        Keyboard.GetState().IsKeyDown(Keys.Escape))
        Exit();

    // TODO: Add your update logic here
    if (!_isBallMoving && TouchPanel.IsGestureAvailable)
    {
        // Read the next gesture
        GestureSample gesture = TouchPanel.ReadGesture();
        if (gesture.GestureType == GestureType.Flick)
        {
            _isBallMoving = true;
            _ballVelocity = gesture.Delta * (float)TargetElapsedTime.TotalSeconds / 5.0f;
        }
    }
    if (_isBallMoving)
    {
        _ballPosition += _ballVelocity;
        // reached goal line
        if (_ballPosition.Y < _goalLinePosition)
        {
            _ballPosition = new Vector2(_initialBallPosition.X, _initialBallPosition.Y);
            _isBallMoving = false;
            while (TouchPanel.IsGestureAvailable)
                TouchPanel.ReadGesture();
        }
        _ballRectangle.X = (int) _ballPosition.X;
        _ballRectangle.Y = (int) _ballPosition.Y;
    }
    base.Update(gameTime);

}

不再保持足球增量:程序使用 _ballVelocity字段从 x 和 y 方向上设置足球速度。 Gesture.Delta可返回上一次更新之后的运动变量。 如要计算轻拂操作的速度,请将该矢量与 TargetElapsedTime属性相乘。

如果足球正在移动,_ballPosition矢量将按照速度(每帧的像素数)增加直至足球到达球门线。 以下代码:

_isBallMoving = false;
while (TouchPanel.IsGestureAvailable)
    TouchPanel.ReadGesture();

. . .可以执行两个操作:它可以让足球停止,也可以移除输入队列的所有手势。 如果你不执行该操作,则用户能够在足球移动时进行轻拂操作,这将会使足球在停止之后再次移动。

当运行该游戏时,你可以轻拂足球,它能够以你轻拂的速度和方向进行移动。 但是,此处有一个问题。 代码无法检测到轻拂操作出现的位置。 你可以轻拂屏幕的任何位置(不仅是足球内部),然后足球将开始移动。 你可以使用gesture.Position检测轻拂的姿势,但是该属性将会一直返回 0,0,因此便无法使用该方法。

解决这一问题的方法是使用原始输入,获取触摸点,然后了解其是否在足球附近。 以下代码能够决定触摸输入是否可以触发足球。 如果可以,手势将设置 _isBallHit field

TouchCollection touches = TouchPanel.GetState();

TouchCollection touches = TouchPanel.GetState();

if (touches.Count > 0 && touches[0].State == TouchLocationState.Pressed)
{
    var touchPoint = new Point((int)touches[0].Position.X, (int)touches[0].Position.Y);
    var hitRectangle = new Rectangle((int)_ballPositionX, (int)_ballPositionY, _ballTexture.Width,
        _ballTexture.Height);
    hitRectangle.Inflate(20,20);
    _isBallHit = hitRectangle.Contains(touchPoint);
}

然后,运动仅在 _isBallHit字段为 True 时开始:

if (TouchPanel.IsGestureAvailable && _isBallHit)

如果运行游戏,你将仅可在轻拂操作启动足球时移动它。 但是,此处仍然存在一个问题:如果点击球的速度太慢或以其无法击中球门线的位置点击,则游戏将会结束,因为足球不会返回起始点。 必须为足球移动设置一个超时。 当到达超时时,游戏便会将足球复位。

Update 方法有一个参数: gameTime。 如果在移动开始时存储了 gameTime值,则可知道足球移动的实际时间,并可在超时后重置游戏:

if (gesture.GestureType == GestureType.Flick)
{
    _isBallMoving = true;
    _isBallHit = false;
    _startMovement = gameTime.TotalGameTime;
    _ballVelocity = gesture.Delta*(float) TargetElapsedTime.TotalSeconds/5.0f;
}

...

var timeInMovement = (gameTime.TotalGameTime - _startMovement).TotalSeconds;
// reached goal line or timeout
if (_ballPosition.Y <' _goalLinePosition || timeInMovement > 5.0)
{
    _ballPosition = new Vector2(_initialBallPosition.X, _initialBallPosition.Y);
    _isBallMoving = false;
    _isBallHit = false;
    while (TouchPanel.IsGestureAvailable)
        TouchPanel.ReadGesture();
}

添加守门员

游戏现在可以运行了,但是它还需要一个制造难度的元素:你必须添加一个守门员,在用户踢出足球后一直运动。 守门员是 XNA 内容编译器编译的 .png 文件(图 6)。 我们必须将该编译文件添加至 Content 文件夹,为 Content 设置构建操作,并将“复制至输出目录 (Copy to Output Directory)”设置为“如果较新则复制(Copy if Newer)”。

图 6.守门员

守门员在 LoadContent方法中加载:

protected override void LoadContent()
{
    // Create a new SpriteBatch, which can be used to draw textures.
    _spriteBatch = new SpriteBatch(GraphicsDevice);

    // TODO: use this.Content to load your game content here
    _backgroundTexture = Content.Load<Texture2D>("SoccerField");
    _ballTexture = Content.Load<Texture2D>("SoccerBall");
    _goalkeeperTexture = Content.Load<Texture2D>("Goalkeeper");
}

然后,我们必须在 Draw方法中绘制它:

protected override void Draw(GameTime gameTime)
{

    GraphicsDevice.Clear(Color.Green);

    // Begin a sprite batch
    _spriteBatch.Begin();
    // Draw the background
    _spriteBatch.Draw(_backgroundTexture, _backgroundRectangle, Color.White);
    // Draw the ball
    _spriteBatch.Draw(_ballTexture, _ballRectangle, Color.White);
    // Draw the goalkeeper
    _spriteBatch.Draw(_goalkeeperTexture, _goalkeeperRectangle, Color.White);
    // End the sprite batch
    _spriteBatch.End();
    base.Draw(gameTime);
}

_goalkeeperRectangle 在窗口中可提供一个矩形的守门员。 它可在 Update 方法中更改:

protected override void Update(GameTime gameTime)
{…

   _ballRectangle.X = (int) _ballPosition.X;
   _ballRectangle.Y = (int) _ballPosition.Y;
   _goalkeeperRectangle = new Rectangle(_goalkeeperPositionX, _goalkeeperPositionY,
                    _goalKeeperWidth, _goalKeeperHeight);
   base.Update(gameTime);
}

_goalkeeperPositionY、_goalKeeperWidth_goalKeeperHeight字段可在 ResetWindowSize方法中更新:

private void ResetWindowSize()
{…
    _goalkeeperPositionY = (int) (_screenHeight*0.12);
    _goalKeeperWidth = (int)(_screenWidth * 0.05);
    _goalKeeperHeight = (int)(_screenWidth * 0.005);
}

守门员最初位于屏幕中央的球门线顶端附近。

_goalkeeperPositionX = (_screenWidth - _goalKeeperWidth)/2;

守门员将会在足球开始移动时开始移动。 它将会不停地以谐运动的方式从一端移动至另一端。 该正弦曲线可描述该运动:

X = A * sin(at + δ)

其中,A是运动幅度(目标宽度),t是运动时间, aδ是随机系数(这将会使运动具备一定的随机性,因此用户将无法预测守门员的速度和方向)。

该系数将会在用户通过轻拂踢出足球时进行计算:

if (gesture.GestureType == GestureType.Flick)
{
    _isBallMoving = true;
    _isBallHit = false;
    _startMovement = gameTime.TotalGameTime;
    _ballVelocity = gesture.Delta * (float)TargetElapsedTime.TotalSeconds / 5.0f;
    var rnd = new Random();
    _aCoef = rnd.NextDouble() * 0.005;
    _deltaCoef = rnd.NextDouble() * Math.PI / 2;
}

系数 a是守门员的速度,0 和 0.005 之间的数字代表 0 和 0.3 像素/秒之间的速度(1/60 秒内最大像素为 0.005)。 delta 系数是必须是介于 0 和 pi/2 之间的数字。 足球移动时,你可以更新守门员的位置:

if (_isBallMoving)
{
    _ballPositionX += _ballVelocity.X;
    _ballPositionY += _ballVelocity.Y;
    _goalkeeperPositionX = (int)((_screenWidth * 0.11) *
                      Math.Sin(_aCoef * gameTime.TotalGameTime.TotalMilliseconds +
                      _deltaCoef) + (_screenWidth * 0.75) / 2.0 + _screenWidth * 0.11);…
}

运动的幅度是 _screenWidth * 0.11(目标尺寸)。 将(_screenWidth * 0.75) / 2.0 + _screenWidth * 0.11 添加至结果,以便守门员移动至目标前方。 现在,开始构建让守门员接住球。

命中测试

如果希望了解守门员是否能够接住球,你需要知道球的矩形是否与守门员的矩形相交。 我们可以按照以下代码计算两个矩形后,在 Update方法中执行该操作:

_ballRectangle.X = (int)_ballPosition.X;
_ballRectangle.Y = (int)_ballPosition.Y;
_goalkeeperRectangle = new Rectangle(_goalkeeperPositionX, _goalkeeperPositionY,
    _goalKeeperWidth, _goalKeeperHeight);
if (_goalkeeperRectangle.Intersects(_ballRectangle))
{
    ResetGame();
}

ResetGame 仅可重构代码,将游戏重置为初始状态:

private void ResetGame()
{
    _ballPosition = new Vector2(_initialBallPosition.X, _initialBallPosition.Y);
    _goalkeeperPositionX = (_screenWidth - _goalKeeperWidth) / 2;
    _isBallMoving = false;
    _isBallHit = false;
    while (TouchPanel.IsGestureAvailable)
        TouchPanel.ReadGesture();
}

借助该简单代码,游戏便可知道守门员是否能够接住球。 现在,我们需要知道足球是否能够命中。 当足球超过球门线时,执行以下代码。

var isTimeout = timeInMovement > 5.0;
if (_ballPosition.Y < _goalLinePosition || isTimeout)
{
    bool isGoal = !isTimeout &&
        (_ballPosition.X > _screenWidth * 0.375) &&
        (_ballPosition.X < _screenWidth * 0.623);
    ResetGame();
}

足球必须完全在目标中,因此,其位置必须在第一个球门柱之后(_screenWidth * 0.375)开始,并在第二个球门柱之前(_screenWidth * 0.625 − _screenWidth * 0.02)结束。 现在,我们开始更新游戏分数。

添加分数记录(Scorekeeping)

如要向游戏中添加游戏记录,我们必须添加一个新资产:spritefont,其字体可用于游戏。 spritefont是描述字体的 .xml 文件,包括字体家族及其尺寸和重量及其他属性。 在游戏中,你可以按照以下方式使用 spritefont:

<?xml version="1.0" encoding="utf-8"?><XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics"><Asset Type="Graphics:FontDescription"><FontName>Segoe UI</FontName><Size>24</Size><Spacing>0</Spacing><UseKerning>false</UseKerning><Style>Regular</Style><CharacterRegions><CharacterRegion><Start> </Star><End></End></CharacterRegion></CharacterRegions></Asset></XnaContent>
你可以使用 XNA 内容编译器来编译该 .xml 文件,并将生成的 .xnb 文件添加至项目的 Content 文件夹;将其构建操作设置至 Content,并将“复制至输出目录(Copy to Output Directory)”设置为“如果较新则复制(Copy if Newer)”。 字体可在 LoadContent方法中加载:
_soccerFont = Content.Load<SpriteFont>("SoccerFont");

ResetWindowSize中,重置得分情况:

var scoreSize = _soccerFont.MeasureString(_scoreText);
_scorePosition = (int)((_screenWidth - scoreSize.X) / 2.0);

如要保持记录,需要声明两个变量: _userScore_computerScore。 命中时,_userScore变量增加,未命中、超时或守门员接住球时,_computerScore增加:

if (_ballPosition.Y < _goalLinePosition || isTimeout)
{
    bool isGoal = !isTimeout &&
                  (_ballPosition.X > _screenWidth * 0.375) &&
                  (_ballPosition.X < _screenWidth * 0.623);
    if (isGoal)
        _userScore++;
    else
        _computerScore++;
    ResetGame();
}
…
if (_goalkeeperRectangle.Intersects(_ballRectangle))
{
    _computerScore++;
    ResetGame();
}

ResetGame 可重新创建得分文本,并设置其情况:

private void ResetGame()
{
    _ballPosition = new Vector2(_initialBallPosition.X, _initialBallPosition.Y);
    _goalkeeperPositionX = (_screenWidth - _goalKeeperWidth) / 2;
    _isBallMoving = false;
    _isBallHit = false;
    _scoreText = string.Format("{0} x {1}", _userScore, _computerScore);
    var scoreSize = _soccerFont.MeasureString(_scoreText);
    _scorePosition = (int)((_screenWidth - scoreSize.X) / 2.0);
    while (TouchPanel.IsGestureAvailable)
        TouchPanel.ReadGesture();
}

_soccerFont.MeasureString 可使用选中字体测量字符串,你可以使用该测量方式来计算得分情况。 得分可在 Draw 方法中进行绘制:

protected override void Draw(GameTime gameTime)
{
…
    // Draw the score
    _spriteBatch.DrawString(_soccerFont, _scoreText,
         new Vector2(_scorePosition, _screenHeight * 0.9f), Color.White);
    // End the sprite batch
    _spriteBatch.End();
    base.Draw(gameTime);
}

打开球场灯光

作为最后一个触摸设计,该款游戏可在室内光线较暗时打开球场灯光。 全新超极本和 2 合 1 设备通常具备一个光线传感器,你可以用它来确定室内光线的程度并更改背景的绘制方式。

对于台式机应用,我们可以使用面向 Microsoft .NET Framework 的 Windows API Code Pack,它是一款支持访问 Windows 7 及更高版本操作系统特性的库。 但是,在该游戏中,我们采用了另一种方式:WinRT Sensor API。 这些 API 虽然面向 Windows 8 而编写,但是同样适用于台式机应用,且不经任何更改即可使用。 借助它们,你无需更改任何代码即可将应用移植到 Windows 8。

英特尔® 开发人员专区(IDZ)包括一篇如何在台式机应用中使用 WinRT API 的文章(详见“了解更多信息”部分)。 基于该信息,你必须在 Solution Explorer 中选择该项目,右击它,然后点击 Unload Project。 然后,再次右击该项目,并点击 Edit project。 在第一个 PropertyGroup中添加 TargetPlatFormVersion标签:

<PropertyGroup><Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
…
  <FileAlignment>512</FileAlignmen><TargetPlatformVersion>8.0</TargetPlatformVersion></PropertyGroup>

再次右击项目,然后点击Reload Project。 Visual Studio 将重新加载该项目。 当向项目中添加新标签时,将能够在 Reference Manager 中看到 Windows标签,如图 7 所示。

图 7.Reference Manager 中的 Windows* 标签

向项目中添加 Windows 参考。 此外,你还需要添加 System.Runtime.WindowsRuntime.dll参考。 如在汇编程序列表中看不到,则可浏览 .Net Assemblies文件夹。 在我的设备上,路径为 C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5

现在,你可以开始编写代码来检测灯光传感器:

LightSensor light = LightSensor.GetDefault();
if (light != null)
{

如果有灯光传感器,GetDefault方法可返回一个非空变量,以便用来检查灯光变化。 通过编写 ReadingChanged事件来执行该操作,如下:

LightSensor light = LightSensor.GetDefault();
if (light != null)
{
    light.ReportInterval = 0;
    light.ReadingChanged += (s,e) => _lightsOn = e.Reading.IlluminanceInLux < 10;
}

如果读取的值小于 10,则变量 _lightsOn为真,你可以用它以不同的方式来绘制背景。 如果你看到 spriteBatchDraw方法,将会发现第三个参数为颜色。 到目前为止,你只使用过白色。 该颜色用于为位图着色。 如果你使用白色,则位图中的颜色将保持不变;如果你使用黑色,则位图将会全部变为黑色。 你可以使用任何颜色为位图着色。 你可以使用颜色来打开灯光,当灯光关闭时使用绿色,开启时使用白色。 在 Draw方法中,更改背景的绘制:

_spriteBatch.Draw(_backgroundTexture, rectangle, _lightsOn ? Color.White : Color.Green);

现在,当你运行程序时,当灯光关闭时你将会看到深绿色背景,当灯光开启时将会看到浅绿色背景(图 8)。

图 8.完整游戏

现在你拥有了一款完整的游戏。 但是,它尚且未完成,它还需要大量改进(命中时的动画,守门员接住球或球击中球门柱时的反弹画面),但是我把它作为家庭作业留给你。 最后一步是将游戏移植到 Windows 8。

将游戏移植至 Windows 8。

将 MonoGame 游戏移植至其他平台非常简单。 你只需要在 MonoGame Windows Store Project类型的解决方案中创建一个新项目,然后删除 Game1.cs文件并将 Windows Desktop 应用 Content文件夹中的四个 .xnb 文件添加至新项目的 Content 文件夹。 你无需向源文件中添加新文件,只需添加链接。 在 Solution Explorer 中,右击 Content 文件夹,点击 “添加/现有文件(Add/Existing Files)”,在 Desktop 项目中选择四个 .xnb 文件,点击“添加(Add)”按钮旁边的下箭头,并选择“添加为链接(Add as link)”。 Visual Studio 可添加四个链接。

然后,将 Game1.cs文件从以前的项目添加至新项目。 重复对 .xnb 文件所执行的流程:右击项目,点击“添加/现有文件(Add/Existing Files)”,从其他项目文件夹中选择 Game1.cs 文件,点击“添加(Add)”按钮旁边的下箭头,然后点击“添加为链接(Add as link)”。 最后需要改动的地方是 Program.cs,你需要对 Game1类的命名空间进行更改,因为你现在使用的是台式机项目中的 Game1类。

完成 — 你创建了一款适用于 Windows 8 的游戏!

结论

游戏开发本身是一项困难重重的任务。 你需要记住三角、几何和物理类,并运用这些概念来开发游戏(如果教授者在教授这些课题时使用的是游戏,会不会很棒?)

MonoGame 让该任务更简单。 你无需处理 DirectX,可以使用 C# 来开发游戏,并且能够完全访问硬件。 你可以在游戏中使用触摸、声音和传感器。 此外,你还可以开发一款游戏,对其进行较小的修改并将其移植至 Windows 8、Windows Phone、Mac OS X、iOS 或 Android。 当你希望开发多平台游戏时,这是一个巨大的优势。

 

了解更多信息

关于作者

Bruno Sonnino 是巴西的微软最有价值专家(MVP)。他是一位开发人员、咨询师兼作家,曾编写过五本有关 Delphi 的书籍,并由 Pearson Education Brazil 以葡萄牙语出版,此外,他还在巴西和美国的杂志和网站上发表过多篇文章。

采用由英特尔® 核芯显卡和锐炬™ 显卡增强的开放标准的 Adobe Photoshop*

$
0
0

Download PDF [1.13MB]

介绍

在本文中,我们将探讨过去几年内,Adobe 工程师使用 OpenGL* 和 OpenCL™ 增强 Photoshop 以提高硬件可用性方面所取得的进步。 Adobe 团队选择了两种特性模糊锐化(Blur Sharpen)和智能锐化(Smart Sharpen)作为近期工作的重心,因为此两者提供的处理速度和质量都不够理想。 我们将在本文中讨论这两种特性的效果。 

开放标准语言、Adobe Photoshop 和英特尔

数年以来,人们一直使用 OpenGL(开放图形语言)提升不同平台间的渲染性能和资源利用率。 OpenCL(开放计算语言)是一款免费的开放标准,支持中央、图形和其他处理器进行可移植、通用及并行编程。 OpenCL 标准是现有 OpenGL API 的补充,可为 OpenGL 使用图形处理器进行渲染提供常规计算例程。 OpenCL 可为开发人员提供统一的编程环境在既定平台内的所有处理资源上执行代码。

Adobe Photoshop是一款领先的图形产业应用,可用于图形编辑和操作。 需要大量处理和内存资源的用户 — Photoshop 是一款强大的应用,要求计算机具备最高的性能。 为支持其图形处理能力,Adobe 在许多代 Photoshop 中使用了开放标准。 它现在已经进行了更新,可利用 OpenCL,这能够提供更高的性能。 

英特尔为该报告提供了测试。 此外,英特尔还提供了大量工具和 SDK 来加速视觉计算的开发。 其中包括适用于英特尔® 处理器的开发人员指南(页面上每一代英特尔图形处理器的指南链接)。 最新指南包括针对第四代英特尔® 酷睿™ 处理器图形的图形开发人员指南 — 现在包括 OpenGL)、针对 OpenCL 应用的英特尔® SDK以及视觉计算专用网站。 

对于一款强大的应用,如 Photoshop,使用诸如 OpenGL 和 OpenCL 等开放标准能够提高性能,支持处理例程跨平台使用,并支持更轻松地使用其他 Adobe 产品。 

Photoshop 之使用 OpenGL 和 OpenCL 标准

数年前,在 Adobe Creative Suite* 4 Photoshop 版(Photoshop CS4)中,Adobe 开发人员将 OpenGL 工作的重心放在增强 Canvas 和 3D 交互上。 他们使用 OpenGL API 实施了 Smooth Zoom、Panning、Canvas Rotate、Pixel Grid 和 3D Axis/Lights 来增强性能。 打开这些特性(在首选项中),启用 “Use Graphics Processor”,选择 “Advanced Settings” 按钮,从下拉菜单中选择 “Advanced Drawing Mode”,勾选“Use Graphics Processor to Accelerate Computation” 和 “Use OpenCL” 的复选框。参考图 1 和图 2,了解 Photoshop 用户界面中的建议设置。

Photoshop on Intel

图 1: Photoshop* 首选项对话框中的图形设置

Photoshop Settings图 2: 在 Drawing Mode 下拉菜单中选择 “Advanced”

借助 Photoshop CS5,开发人员使用了 OpenGL 来加速用户界面(UI)和添加 Pixel Bender 插件。目标 UI 特性包括 Scrubby Zoom、HUD Color Picker、Color Sampling Ring、Repousse 和 3D Overlays。 借助这些新特性,OpenGL 模式扩展至基本、常规和高级方法。

然后,在 Photoshop CS6 中,该团队使用 OpenGL 和 OpenCL 中的标准化特性强化了内容编辑。 开发人员使用 OpenGL 添加了 Adaptive Wide Angle、Liquify、Oil Paint、Puppet Warp、Lighting Effects 和 3D Enhancements。 他们还使用 OpenCL 标准添加了 Field/Iris Tilt/Shift 功能和 Blur 功能。

今天,借助最新版 Adobe Creative Suite,Creative Cloud 可使用 Smart Sharpen 以及可选的 “Use Graphics Processor” 和 “Use OpenCL” 模式进一步增强 Photoshop 应用。

支持 OpenGL 和 OpenCL 的英特尔核芯显卡设备

以下英特尔图形设备需要默认面向 OpenGL 和 OpenCL 图形加速启用:

  • 第四代英特尔® 酷睿™ 处理器
    • 英特尔® 核芯显卡 4200、4400、4600、P4600、P4700
    • 核芯显卡 5000
    • 锐炬™ 显卡 5100
    • 锐炬™ Pro 显卡 5200
  • 第三代英特尔® 酷睿™ 处理器
    • 英特尔® 核芯显卡 4000、P4000
  • 第二代英特尔® 酷睿™ 处理器
    • 英特尔® 核芯显卡 3000、P3000

开发特定 Photoshop 增强特性

开发人员如何实现这些成果? Photoshop 使用了一套图层将许多高级特性应用至图像。 图 3 解释了这一概念,它将一个非常简单的图像的三个图层展示为白色空间。 示例中的效果、红色和蓝色图层在堆栈中是单独图层。 可应用到图层中的效果包括锐化、模糊和红眼去除。 无需改变源文件即可将效果应用至最终图像。 此外,用户还可对这些图层进行整理、堆叠和结合以提供混合效果(见右图),如将红色和蓝色组合在一起得到紫色(PURPLE)。 此外,还包括一些特殊图层,称 “mask layer”,它可以限制应用至指定图像区域的效果。

Photoshop on Intel图 3: 单独(左侧)和组合(右侧)图层

此外,图像结合也适用于 Photoshop 纹理。 Photoshop 纹理是指使用其他图层与现有图层混合,或对其进行覆盖,从而使图像呈现“纹理化”。 注意下图中,左下侧的砖块如何在透明度较低的情况下,为中间图像中雕像的斗篷提供纹理。

Photoshop on Intel图 4: 使用 Photoshop* 中的纹理的示例

Adobe 使用了 OpenGL API 来增强 Photoshop 纹理/图层效果。 在 OpenGL Advanced Mode 中,OpenCL 的 “”调用支持着色工具(Shader Tool)应用棋盘格滤镜合成、色调映射和配色。

锐化焦点

运动照片中广泛使用锐化步骤,因为只需增加一些控制便可对动态照片产生很大的影响。 图 5 展示了如何通过在照片编辑时应用锐化步骤来改进细节。 注意,右侧的“锐化后”图像中,文本、星星甚至笔触细节都更加显著。

Photoshop on Intel图 5: 原始图像(左)和锐化后图像(右)

但是,锐化后步骤可能会产生一些多余的负效果。 原始图像中相对清晰或不重要的细节会产生人造的效果,这类似于增加了图像的“噪音”,从而产生光晕效果。 在该版本中,Adobe 采用了使用 OpenCL 标准实施的基于分块的“降噪和锐化”算法,对传统智能锐化进行了革新。 全新的基于分块的算法可生成没有任何光晕效果的清晰图像。 此外,降噪步骤抑制了“进行锐化时“噪音”增强”的问题。 比较以下图 6、图 7 和图 8 中的图像。 借助该结果,Adobe 希望使用这些标准进一步改进所有的锐化工具。

Photoshop on Intel图 6: 原始文本图像

Photoshop on Intel图 7: 应用了传统智能锐化的图像(带有光晕效果)

Photoshop on Intel图 8: 应用可基于分块的智能锐化的图像

在焦点中应用模糊(Blur)功能

使用 OpenCL 能够改善的另一种编辑工具功能是 Blur 工具。 有许多方法可以强调和模糊图像的某一部分。 许多质量是在照片拍就时形成的,但是经过一些后期处理,能够改进,至少改变照片的效果。 红眼去除和裁剪是非常常见的后期处理任务,而图像的清晰度也能够进行改进。 特定图像区域锐化能产生很大的影响。

Photoshop on Intel图 9: 蒙娜丽莎(Francesco del Giocondo 的妻子 Lisa Gherardini 的画像)画家:列奥纳多·达·芬奇

在作品《蒙娜丽莎》中,列奥纳多·达·芬奇(图 9)[8]通过将蒙娜丽莎的图像置于有些许散焦的乡村风景之前来强调其在肖像中的主题。 通过对背景进行模糊处理,他帮助观者将焦点放在其主题(画作中最重要的部分)而非背景。 以下是模糊处理如何改进现代图像的示例。 我们很难找到照片的主题,模糊处理能够帮助突出图像的主题。 我以图 6 中使用的锐化图像为例,通过应用 Blur 工具进一步强调图像中央的星星,这将会让星星在右下方的图像中更清晰(图 10)。 模糊处理能够改变我们看图像的角度,因此星星能够更突出。 毋庸置疑,有许多方法可以对图像进行模糊处理(出于特定目的),而这种方法最新。

Photoshop on Intel
图 10: 原始图像(左)锐化(中)后,添加了 Blur(右)进行强调

向图像添加 Blur 如同使用了彩色蜡笔,只是在这里,鼠标是蜡笔,颜色是 Blur 功能。 如要应用 Blur,需要选择 Blur 工具,调整 “笔刷(brush)”工具(可从 1 个屏幕像素调整至整个图像尺寸的光标)的尺寸,以符合想要进行模糊处理的图像区域的尺寸,然后点击并按住鼠标并对想要进行模糊处理的图像区域 “着色或擦除(coloring or scrubbing)”。 执行越多的着色操作,就会有越多的模糊效果应用到图像区域。

英特尔增强图形性能

添加 OpenCL Blur 工具的操作提出了一些挑战,也提供了一些好的学习机会。 该团队希望利用主机平台上的所有资源来平衡工作负载。 跨平台操作包括 Windows* 和 Mac* OS 至关重要。 这些因素促使他们选择了 OpenCL。 该团队最终选择了 Photoshop 中现有的模糊化工具,并将其从优化的 CPU 代码中移植至 OpenCL 内核。

Adobe 希望降低 Blur 的复杂性,未采用 OpenCL 以前需要在多个线程上运行多个命令队列。 此外,他们还在低端视频子系统上遇到资源限制的问题,如超时和内存不足故障。 最终,他们通过使用基于 OpenCL 的解决方案降低了平台变量,如驱动程序堆栈以及多种编译器的使用。  借助 OpenCL,他们能够将部分图像缓存至本地内存并为图形处理器将图像分解为 2k X 2k 数据块,从而大幅降低挑战。 这些改进带来更高的可靠性,并通过利用 GPU 将过滤速度提高了 4-8 倍。

英特尔的测试表明,以下 Photoshop 操作的性能得到提升,因为随着英特尔核芯显卡不断更新换代,可用的执行单元和内存带宽不断提升,如下图所示(图 11)。[1]

Photoshop on Intel
图 11: 基于多代英特尔核芯显卡的具备 OpenGL* 性能的 Photoshop*

在进行测试时启用和禁用 OpenGL 或 OpenCL 特性,我们发现例程将会大幅提升 Liquify Filter 和 Field Blur 工具的性能,详见下图(图 12)。 在英特尔® 核芯显卡 4600 上,关闭/开启 1 GPU 加速时 Liquify 和 Blur 处理时间一般为数秒钟。[1]

Photoshop on Intel图 12: 开/关标准时的 Photoshop* 工具性能

该操作非常有用。 在开、关 OpenCL 硬件加速的情况下进行测试时,该款全新 Blur 功能的处理速度提高了 3 倍,具体取决于工作负载和正在渲染的范围尺寸(图 13)。[1]

Photoshop on Intel
图 13: 样本模糊化处理功能执行时间(单位:秒)比较

一般的应用处理所需的时间仅占较小工作负载的大部分,因此较大的工作负载在处理时间上能够获得更大的改进。 当启用 OpenCL 加速时,CPU 和 GPU 都能够有效利用,而且许多多线程应用的核心都能够向图形处理器提交工作。 图形处理单元的最低利用率为 70%,内存利用率为 10%-36%,具体取决于图形子系统。 最后,图形管线中没有停顿,这能够提供更出色的用户体验。

总结

添加基于标准的处理例程让 Adobe 能够继续其在每个版本中增强 Photoshop 性能的传统。 通过在英特尔核芯显卡设备上添加基于 OpenCL 的加速,用户能够获得更高的性能,并且能够在整个图像中实时评估模糊滤波器。 向这些过滤器中添加 OpenCL 之前根本无法获得如此完整的图像体验,而且 OpenCL 的添加还支持更有效地创建出色图像。 在添加 OpenCL 之前,应用效果之前只能预览一小部分的图像。 而现在,用户能够在进行调整时全屏查看只能锐化过滤器,并能够更快地获得所需的最终图像。 采用 OpenCL 后,Photoshop 的性能得到显著提升。



[1]结果基于英特尔内部分析结果,仅供参考。 任何系统硬件、软件的设计或配置的不同均可能影响实际性能。

 

参考资料和资源

作者介绍

Tim Duncan 是一位英特尔工程师,被朋友们成为“Gidget-Gadget 先生”。 Tim 目前负责帮助开发人员将技术集成至解决方案,他在芯片制造和系统集成领域有着数十年的经验。 如欲对其有更多了解,请访问英特尔® 开发人员专区:Tim Duncan (英特尔)

Murali Madhanagopal 是英特尔视觉与并行计算事业部的一员,他在其中担任首席图形架构师。 他获得了德州农工大学学院站(Texas A&M University, College Station)计算机信息系统专业的理学硕士,并获得印度安那大学金奈工程学院(College of Engineering Guindy, Anna University)计算机工程学士学位。 Madhanagopal 主要负责开发和执行英特尔工作站处理器图形策略,以支持 ISV 软件在当前和未来基于处理器显卡的平台上高效运行。 此外,他还积极参与到业内领先的 CAD、CAE 和数字内容创建 ISV 和 OEM 优化应用和系统的活动中。

英特尔、Intel 标识、Iris 和锐炬是英特尔公司在美国和/或其他国家的商标。
OpenCL 和 OpenCL 标识是苹果公司的商标,需获得 Khronos 的许可方能使用。
英特尔公司 © 2014 年版权所有。 所有权保留。
* 其他的名称和品牌可能是其他所有者的资产。

OpenCL™ 主机代码基本示例

$
0
0

Download PDF [686.3 kB]

Download Sample OCL ZIP [10.89 mB]

目录

  1. 介绍
  2. 示例介绍
  3. OpenCL 实施。
  4. 限制
  5. OpenCL 应用基本原理。
  6. 项目结构。
  7. 所使用的 OpenCL API。
  8. 控制示例。
  9. 参考文献。

介绍

新接触 OpenCL 的编程人员可能会发现,最完整的文档 Khronos OpenCL 规范并不适合作为 OpenCL 编程的开始。 该规格介绍了许多选项和备选方案,最初可能会让编程人员晕头转向。   其他面向 OpenCL 编写的代码示例可能主要使用设备内核代码,或使用用 OpenCL “包装器”库编写的主机代码,这会隐藏如何直接使用标准 OpenCL 主机 API 的具体细节。  

本文中介绍的 SampleOCL旨在呈现清晰、可读的复杂(non-trivial)OpenCL 程序的基本元素。 该示例代码是面向主机(CPU)而非内核代码或性能 OpenCL™ 代码。  它展示了如何使用 OpenCL v1.2 规范构建一个简单的 OpenCL 应用的基本原理。[1] 同样,本文主要介绍了主机代码的结构以及该代码使用的 OpenCL API。

示例介绍

该代码示例使用的 OpenCL 内核与 ToneMapping 示例相同(参见下文参考文献),后者曾在面向 OpenCL 应用的英特尔® SDK 中发布[2]。 该简单内核旨在帮助由于太暗或太亮而分辨不清的图片清晰可见。 它从输入缓冲区中读取像素,对其进行修改,然后将其编写至输出缓冲区的同一位置。 关于该内核如何运行的更多信息,请参见文档高动态范围色调映射后期处理效果(High Dynamic Range Tone Mapping Post Processing Effect )[3]。

OpenCL 实施

SampleOCL 示例应用并不是要“包装” OpenCL,也就是说,它并非要使用“更高级的” API 来替换 OpenCL API。 总体而言,我发现,这些包装器不比直接使用 OpenCL API 更简单或更整洁,而且,虽然最初创建包装器的编程人员认为其使用起来更简单,但是包装器会对维护代码的 OpenCL 编程人员带来很大负担。 OpenCL API 是一个标准。 如要在专门的“改进” API 中对其进行包装,则需要丢弃许多使用该标准时的值。

依次说法,SampleOCL 实施的确使用了一些 C++ 类及相关方法将 OpenCL API 分成了几组。 该应用主要分为两大类,以区分通用应用元素和与 OpenCL 相关的元素。 前者是 C_SampleOCLApp,后者是 C_OCL。

限制

该示例代码仅关注 OpenCL 应用的基本原理,如版本 1.2 中的说明。 它并没有介绍与其他修订版之间的不同,但是其大部分信息应与最新修订版相关。

该示例的主机端应用代码并非要展示最优性能。 简便起见,我们将多个明显的优化略去。

OpenCL 应用基本原理

接下来,我们将对基本 OpenCL 应用程序序列进行完整的介绍。 我们在此强调“基本”,因为有许多选项并未涉及。 更多信息请参见 OpenCL 规范[1]。

OpenCL 应用需要能够在多处理设备上大规模并行,如采用 SIMD 指令和图形处理单元(GPU)的多核 CPU — 无论是独立还是集成至 CPU。 因此,OpenCL 应用首先需要能够确定哪些设备可用,并选择一台或多台设备进行使用。 一个平台可能支持多种设备,如包括集成 GPU 的 CPU,而且应用能够使用多个平台。

OpenCL 应用的每个可用平台都包括相关的名称、厂商等。该信息可通过使用 OpenCL API clGetPlatformIDs(),然后再使用 clGetPlatformInfo() 来获取,而且可用于选择目标平台。

选定平台后,必须创建一个环境(context)来实施应用所需的 OpenCL 设备、内存和其他资源。 拥有所选平台 ID 和目标设备类型(CPU、GPU 等)的规范后,应用便能够调用 clCreateContextFromType(),然后使用 clGetContextInfo() 来获取设备 ID。 或者,它可以直接使用 clGetDeviceIDs() 在给定平台 ID 上请求设备 ID,然后使用带有这些设备 ID 的 clCreateContext() 创建环境。 本示例使用了第二种方法来创建带有一个 GPU 设备的环境。

拥有目标设备 ID 和环境后,我们便可使用 clCreateCommandQueue() 为每台要使用的设备创建命令队列。 命令队列用于主机应用至 GPU 或其他设备的“排队”操作,例如,申请执行某个 OpenCL 内核。 本示例代码为 GPU 设备创建了一个命令队列。

初始化操作完成后,通常我们接下来将会使用 clCreateProgramWithSource() 创建一个或多个 OpenCL 程序对象。 程序创建后,它还需要使用 clBuildProgram() 进行构建(基本的编写和链接)。 该 API 支持为编译器设置选项,如设置 #defines 以修改程序源代码。

最后,借助创建和构建的程序,我们可创建链接至该程序中的函数的内核对象,从而为每个内核函数名称调用 clCreateKernel()。

运行 OpenCL 内核前,需要先设置要处理的数据,通常通过使用 clCreateBuffer() API 函数创建线性内存缓冲区来完成。 (本示例中未使用映像作 为 OpenCL 内存对象类型。) clCreateBuffer 函数可为既定尺寸的缓冲区分配内存,并可随意从主机内存复制数据,而且,它能够设置缓冲区,以直接使用主机代码已经分配的空间。 (后者能够避免从主机内存复制至 OpenCL 缓冲区,这是常见的性能优化。)

一般而言,内存将至少使用一个输入和一个输出缓冲区以及其他参数。 每次只能设置一个参数,以便内核在执行时访问。访问时只需调用每个参数的 clSetKernelArg() 函数即可。 该函数可使用内核函数参数列表中的一个特殊参数 — 数字索引进行调用。 第一个参数使用 index 0 传递,第二个参数 index 1 等。

借助参数集,调用包含内核对象和命令队列的函数 clEnqueueNDRangeKernel(),申请运行该内核。 内核排队后,主机代码可以做其他的事情,或者可以通过调用 clFinish() 函数等待内核(及之前加入队列的所有任务)完成。 本示例可以调用 clFinish(),因为它包括能够记录一个循环中总内核执行(包括所有排队开销)的时间,该循环需要等待所有执行都完成后, 才能记录最终时间或得出平均时间。

以上是构建 OpenCL 应用的部分。 此外,还有一些清除操作,如调用 clReleaseKernel、clReleaseMemObject、clReleaseProgram 等。虽然 OpenCL 在程序退出时应自动释放所有资源,但是本示例中仍包括这些操作。 较为复杂的程序可能希望即时释放资源以避免内存泄露。

最后应注意的一点是:虽然本示例没有使用“事件”,但是它们对于(比如)希望覆盖 CPU 和 GPU 处理的复杂应用非常有用。 但是,应注意到,任何将指针传递至事件的 clEnqueueXXXXX() 函数(其中 “XXXXX” 用众多可行函数中一个的名称进行替换)都将分配一个事件,然后调用代码负责在某一时刻将包含指针的 clReleaseEvent() 调用至事件。 如果该操作未完成,随着事件累积,程序将会出现内存泄露。

常见的错误是使用 clCreateUserEvent() 函数分配事件以传递至 clEnqueueXXXX 函数,这种操作认为完成后 OpenCL 将会标记该事件。 OpenCL 不会使用该事件,clEnqueueXXXX 将会返回新事件,覆盖指针传递的事件变量的内容。 这种方式很容易导致内存漏洞。 除了本示例的范围以外,用户事件还有其他目的。 关于 OpenCL 事件的更多详细信息,请参见 OpenCL 规范。[1]

项目结构

_tmain ( argc, argv ) - Main.cpp文件中的主要接入点函数。

创建 C_SampleOCLApp类的实例。

调用 C_SampleOCLApp::Run() 以启动应用。

这是它的全部功能! 参见以下 C_MainApp 和 C_SampleApp 类了解更多信息。

C_MainApp类 - C_MainApp.h文件中的通用 OpenCL 应用超类(super-class)

构建时,创建 OpenCL 类 C_OCL的实例。

 

定义通用应用 “run” 函数:

Run()

Run() 是读取代码以理解 OpenCL 应用如何初始化、运行和清理的良好起点。

Run() 可调用具有代表性的简单应用序列中的虚拟函数(见下文)。

 

声明要由 C_SampleOCLApp定义的虚拟函数(见下文):

AppParseArgs ()

解析命令行选项

AppUsage ()

打印使用说明

AppSetup ()

应用设置,包括 OpenCL 设置

AppRun ()

特定应用操作

AppCleanup ()

应用清除

 

C_SampleOCLApp类 - 来自 C_MainApp,可专门针对本示例定义函数。

SampleApp.cpp SampleApp.h文件中的 C_MainApp虚拟函数实施应用特定代码。 (参见 C_MainApp类(见上文),了解实施的虚拟函数。)

ToneMap_OCL.cpp 文件中定义 "ToneMap" OpenCL 内核设置和运行函数:

RunOclToneMap ()

为 ToneMap 执行一次性设置,然后调用 ToneMap()。

ToneMap ()

设置 ToneMapping 内核参数并运行该内核。

 

C_OCL类 - 大部分的主机端 OpenCL API 可设置并清理代码。

构建时,初始化 OpenCL。 销毁时,在 OpenCL 之后清除。

C_OCL.cpp C_OCL.h文件中定义 OpenCL 服务函数:

Start ()

为适当平台的英特尔® 锐炬™ 显卡设置 OpenCL 设备。

ReadAllPlatforms ()

获取所有可用 OpenCL 平台,保存其名称。

MatchPlatformName ()

辅助函数,可通过名称来选择平台。

GetDeviceType ()

辅助函数,可确定设备类型是 GPU 还是 CPU。

CheckExtension ()

检查某个 OpenCL 扩展名是否能够在目前的设备上使用。

ReadExtensions ()

获取列出当前设备的所有 OpenCL 扩展名的字符串。

SetCurrentDeviceType ()

设置目标设备类型并创建 OpenCL 环境和命令队列。

CreateProgramFromFile ()

加载包含 OpenCL 内核的文件,创建 OpenCL 程序并对其进行构建。

ReadSourceFile ()

将 OpenCL 内核源文件读入字符串,准备将其构建为程序。

CreateKernelFromProgram ( )

从以前构建的程序中创建 OpenCL 内核。

GetDeviceInfo ()

获取设备特定信息的两个辅助函数:其一可分配内存以接收和返回结果;其二可通过指针将结果返回至调用程序提供的内存。

ClearAllPlatforms ()

释放与以前选中的平台相关的所有内容。

ClearAllPrograms ()

释放所有现有 OpenCL 程序。

ClearAllKernels ()

释放所有现有 OpenCL 内核。

 

所使用的 OpenCL API

clBuildProgram

clCreateBuffer

clCreateCommandQueue

clCreateContext

clCreateKernel

clCreateProgramWithSource

clEnqueueMapBuffer

clEnqueueNDRangeKernel

clEnqueueUnmapMemObject

clFinish

clGetDeviceIDs

clGetDeviceInfo

clGetPlatformIDs

clGetPlatformInfo

clReleaseCommandQueue

clReleaseContext

clReleaseDevice

clReleaseDevice

clReleaseKernel

clReleaseMemObject

clReleaseProgram

clSetKernelArg

控制示例

本示例从 Microsoft Windows* 命令行控制台运行。 它支持以下命令行和可选参数:

ToneMapping.exe [ ? | --h ] [-c|-g] [-list] [-p "platformName] [-i "full image filename"]

? OR --h

打印该帮助消息

-c

在 CPU 上运行 OpenCL

-g

在 GPU 上运行 OpenCL — 默认

-list

显示平台名称字符串列表

-p "platformName"

提供平台名称(如果有空间将会用引号标出)以供检查和使用。

-i "full image filename"

提供图像文件名称(如果有空间将会用引号标出)以供处理。

参考文献

  1. OpenCL Specifications from Khronos.org:

    http://www.khronos.org/registry/cl/

  2. Intel® SDK for OpenCL™ Applications:http://software.intel.com/en-us/vcsource/tools/opencl-sdk
  3. High Dynamic Range Tone Mapping Post Processing Effect:

    http://software.intel.com/en-us/vcsource/samples/hdr-tone-mapping

 

英特尔、Intel 标识、 Iris 和锐炬是英特尔在美国和其他国家的商标。
* 其他的名称和品牌可能是其他所有者的资产。
OpenCL 和 OpenCL 标识是苹果公司的商标,需获得 Khronos 的许可方能使用。
英特尔公司 © 2014 年版权所有。 所有权保留。


为使用英特尔® 通用连接框架的 Windows* 8 开发数据传输应用

$
0
0

Download PDF

英特尔® 通用连接框架(英特尔® CCF)是一款面向移动设备上运行的应用的连接软件。 使用英特尔 CCF 的应用能够将所有用户连接在一起,无论其在世界的另一端使用者不同的防火墙,还是同处一室但没有连接互联网。 英特尔 CFF 适用于 iOS*、Android*、Windows* Desktop 和 Windows 商店的所有应用,这些应用可在任意平台上使用任何外形的英特尔 CCF。 使用英特尔 CCF,开发人员能够开发在手机、平板电脑、PC 和其他智能设备上使用的应用。

英特尔 CFF 的通信模型是对等的方式。 它支持人们直接与彼此连接,并分享其所有移动计算设备间的信息。

本文中,我将介绍如何使用英特尔 CCF 3.0 为 Windows 8 设备开发应用。 我曾负责开发能够在 Windows 8 和 Android 设备之间传输文件的应用的项目,在该项目中,我独立开发了一款 Windows 应用商店应用。 在这里,我将与大家分享使用英特尔 CCF 的经验。

首先,你需要在 Microsoft Visual Studio* 中将 lib 文件与该项目相关联。 英特尔 CCF SDK 包含两个 dll 文件:libMetroSTC 和 WinRTSTC,所有英特尔 CFF 应用都需要这两个文件。 如要使用英特尔 CCF API,需要将 Intel.STC.winmd 添加至项目参考。 winmd 文件包含使用英特尔 CFF SDK 构建 Windows 应用商店应用的元数据。

身份设置

在将会话显示前,英特尔 CCF 用户必须先设置身份,包括用户名、设备名和 avatar。 这是远程用户将看到的身份。 在面向 Windows 应用商店应用的 SDK 中,InviteAssist 类支持用户设置英特尔 CCF 身份。

                string displayName = await UserInformation.GetDisplayNameAsync();
                _inviteAssist = InviteAssist.GetInstance();
                _inviteAssist.SetUserName(displayName);
                _inviteAssist.SetStatusText("Status");
                _inviteAssist.SetSessionName("Win 8");
                if (_AvatarStorageFile == null)
                {
                    Windows.Storage.StorageFile imgfile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/Device.png"));
                    _AvatarStorageFile = imgfile;
                }
                await _inviteAssist.SetAvatarAsync(_AvatarStorageFile);

实施 SetUserProfile() 函数获取 InviteAssist 类的实例,通过调用 InviteAssist.SetUserName()、InviteAssist.SetSessionName() 和 InviteAssist.SetAvatarAsync() API 设置配置文件,如下所示。 我将用户名设置为 Windows 账户名,我的 Windows 8 设备将连接的所有设备上都能看到该指派。 状态文本和会话名可由用户在 UI 中定义。 在我的案例中,这些参数不能被用户更改,且一直使用我的符号。 现在,配置文件已设置完成并可由远程用户发现。

发现

英特尔 CCF 远程用户发现可通过调用 Intel.STC.Api.STCSession.GetNeighborhood() API 来完成,它能够返回发现的所有远程 STCSessions 的 IObservableVector<object>。 开发人员需要负责在 observable collection 与 UI 之间实施数据绑定(Data Bind),或从背后的代码更新 UI 以显示用户列表。 我使用了 Grid APP (XAML),它是 Visual Studio 中渲染 GUI 的标准模板。 GridList 结果中显示的所有用户。

为 NeighborhoodUsers 类对象创建一个 ObservableCollection。 _userList 是 STCSession 类对象的列表,并包括周围用户(neighborhood user)列表。

private static List<STCSession> _userList;
	IObservableVector<object> _hood;
	ObservableCollection<NeighborhoodUsers> _neighborhoodList = new ObservableCollection<NeighborhoodUsers>();
        ObservableCollection<NeighborhoodUsers> neighborhoodList
        {
            get { return _neighborhoodList; }
        }
通过调用 STCSession.GetNeighborhood()API 获取 IObservableVector,并为 IObservableVector 设置 VectorChanged 事件处理程序。
	async void GetNeighborhoodList()
        	{
            		await Task.Run(() =>
          		  {
               	 	_hood = STCSession.GetNeighborhood();
                		_hood.VectorChanged += _hood_VectorChanged;
                		STCSession.LockNeighborhood();
                		IEnumerator<object> en = _hood.GetEnumerator();
                		while (en.MoveNext())
                		{
                    			STCSession session = en.Current as STCSession;
                    			if (session != null)
                        				hood_DiscoveryEvent(session, CollectionChange.ItemInserted);
                		}
                		STCSession.UnlockNeighborhood();
            		});
        	}

        	void _hood_VectorChanged(IObservableVector<object> sender, IVectorChangedEventArgs evt)
        	{
            		STCSession session = null;
            		lock (sender)
            		{
                		if (sender.Count > evt.Index)
                    			session = sender[(int)evt.Index] as STCSession;
            		}
            		if (session != null)
                		hood_DiscoveryEvent(session, evt.CollectionChange);
        	}

我们添加 hood_DiscoveryEvent() 回调函数以捕获矢量变化事件。 当远程会话可以进行连接,或无法在周围(neighborhood)继续使用时,该回调函数将会发出通知。 当新会话可用时,将会接收到 CollectionChange.ItemInserted 事件;当远程 STCSession 离开周围(neighborhood)或 STCSession 参数发生改变时,将会接收到 CollectionChange.ItemRemoved 和 CollectionChange.ItemChanged 事件。 添加 STCSession.ContainsGadget(),以查看远程设备上是否安装了相同的应用。

private async void hood_DiscoveryEvent(STCSession session, CollectionChange type)
        	{
            		switch (type)
            		{
                		case CollectionChange.ItemInserted:
                    			await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                    {
                        			_userList.Add(session);
                        			AddPeopleToList(session, "Not Connected");
                    });

                    		break;

                		case CollectionChange.ItemRemoved:
			// Handle this case to check if remote users have left the neighborhood.
                    			if (_neighborhoodList.Count > 0)
                    			{
                        				NeighborhoodUsers obj;
                        				try
                        				{
                            				obj = _neighborhoodList.First((x => x.Name == session.User.Name));
                            				await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                            {
                                	_neighborhoodList.Remove(obj);
                                	_userList.RemoveAll(x => x.Id.ToString() == session.Id.ToString());
                            });
                        				}
                        				catch
                        				{
                            				obj = null;
                        				}
                    			}
                   		 break;
                		case CollectionChange.ItemChanged:
			// Handle this case to check if any STCSession data is updated.
                   		 {
                        			STCSession item;
                        			try
                        			{
                            			item = _userList.First(x => x.Id == session.Id);
                        			}
                        			catch
                        			{
                            			item = null;
                        			}
                        			if (item != null)
                           			 item.Update(session);
                        			break;
                  		}
                		default:
                    		break;
            		}
       	 }

 

邀请(Invitation)

我们已经知道了如何发现远程用户(设备),现在应该了解发送连接的流程。 在英特尔 CCF,该流程成为“邀请”。 在英特尔 CCF 3.0, 发送和接收“邀请”通过 STCInitiator 和 STCResponder 进行控制。 STCInitiator 用于向远程用户发送“邀请”,STCResponder 用于响应入站请求。 远程用户接收请求后,将成功建立英特尔 CCF 连接。 使用 STCInitiator 对象发送“邀请”没有任何限制。 一个对象可以发送多个“邀请”。

我们将在以下函数中介绍向远程用户发送邀请。

private void InitializeInitiator(STCApplicationId appId)
        	{
            		initiator = new STCInitiator(appId, true);
            		initiator.InviteeResponded += initiator_InviteeResponded;
            		initiator.CommunicationStarted += initiator_CommunicationStarted;
            		initiator.Start();
        	}

设置完所有调用处理程序后,则调用 STCInitiator.Start() API。 现在,如要向发现的远程用户发送“邀请”,则需要调用 STCInitiator.Invite() API。

initiator.Invite(_userList[itemListView.Items.IndexOf(e.ClickedItem)].Id);

如要查看所发送的“邀请”的状态,需要实施 STCInitiator.InviteeResponded() 回调。

async void initiator_InviteeResponded(STCSession session, InviteResponse response)
{
		await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
		{
  			switch(response)
			{
				case InviteResponse.ACCEPTED:
                			// You are connected to the user.
				break;
				case InviteResponse.REJECTED:
                			//Invite was rejected by the remote user.
				break;
		        		case InviteResponse.TIMEDOUT:
                			//No response. Invite time-out.
				break;
                		}
        		});
}

“邀请”已发送,远程用户需要接收它。 实施调用 InitializeResponder() 的函数,通过传递 STCApplicationId 对象初始化 STCResponder 对象。 注册 STCResponder.InviteeResponded() 和 STCResponder.CommunicationStarted() 处理程序。 当远程用户响应“邀请”,或当两个英特尔 CCF 用户之间的通信通道成功建立时,将会调用这些处理程序。

	private void InitializeResponder(STCApplicationId appId)
        	{
            		responder = new STCResponder(appId);
          		  responder.InviteReceived += responder_InviteReceived;
            		responder.CommunicationStarted += responder_CommunicationStarted;
            		responder.Start();
      	  }

远程用户发送的“邀请”可在 STCResponder.InviteReceived() 回调中接收。 接收到“邀请”后,可以接受也可以拒绝。 为响应该“邀请”,需要调用 STCResponder.RespondToInvite() API。

STCResponder.RespondToInvite() API is called.
	async void responder_InviteReceived(STCSession session, int inviteHandle)
        	{
            		if ((_initiatorDataStream == null) && (_responderDataStream == null))
            		{
                		try
                		{
                    			if (!checkPopUp)
                    			{
                        				_inviteHandle = inviteHandle;
                        				_session = session;
                        				Debug.WriteLine("Several windows " + _inviteHandle);
                        				checkPopUp = true;
                        				await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                        			{
                            				InviteeName.Text = session.User.Name + " wants to connect";
                            				InviteePopup.IsOpen = true;
                            				checkPopUp = true;
                        			});
                		    	}
                		}
                		catch (Exception ex)
                		{
                    			Debug.WriteLine(ex.Message);
                		}
            		}
            		else
            		{
                		responder.RespondToInvite(session, inviteHandle, false);
            		}
        	}

通信和数据传输

发送和接收“邀请”后,initiator_CommunicationStarted() 和 responder_CommunicationStarted() 回调将提供流处理(Stream handle)。 我们将使用该 NetStream 处理在两个互联用户之间传输数据。 如要获得数据流处理,则需要实施 initiator_CommunicationStarted() 和 responder_CommunicationStarted() callbacks 并创建 NetStream 对象。 可以注册对 NetStream.StreamClosed 和 NetStream.StreamSuspended 事件的回调。 当通信通道关闭或暂停时,将会接收到这些事件。

void initiator_CommunicationStarted(CommunicationStartedEventArgs args)
        	{
            		_initiatorDataStream = args.Stream;

            		objWrapper.SetStream(_initiatorDataStream);

            		_initiatorDataStream.StreamClosed += DataStream_StreamClosed;
            		_initiatorDataStream.StreamSuspended += DataStream_StreamSuspended;
            		_initiatorDataStream.DataReady += objWrapper.StreamListen;
       	 }
        	void responder_CommunicationStarted(CommunicationStartedEventArgs args)
        	{
            		_responderDataStream = args.Stream;

            		objWrapper.SetStream(_responderDataStream);

            		_responderDataStream.StreamClosed += DataStream_StreamClosed;
            		_responderDataStream.StreamSuspended += DataStream_StreamSuspended;
            		_responderDataStream.DataReady += objWrapper.StreamListen;
      	  }

	private async void DataStream_StreamClosed(int streamId, Guid sessionGuid)
        	{
            		await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            		{
               		 UpdateConnectionStatus(_session.User.Name, "Not Connected");
              			  if (_inviter)
               		 {
                   			 _initiatorDataStream.Dispose();
                    			_initiatorDataStream = null;
                    			_inviter = false;
                		}
                		else if (_responder)
                		{
                    			_responderDataStream.Dispose();
                    			_responderDataStream = null;
                    			_responder = false;
                		}
                		if (isTransferFrame)
               		{
                    			if (this.Frame != null && this.Frame.CanGoBack) this.Frame.GoBack();
                		}
                	ResetUIScreen();
            		});
        	}

现在,我们来看一下数据传输流程。 首先,我们选择想要发送的文件。 对于这一点,我开发了自己的文件管理器,但是选择文件更简单的方式是使用 FileOpenPicker。 选择文件后,将数据编写至接收到的 NetStream 处理中。 如要在通信通道上编写数据,则需要使用 NetStrem.Write()。

async void SendFileData()

async void SendFileData()
       	{
           		uint size = 1024 * 4;
           		byte[] buffer = new byte[size];
           		int totalbytesread = 0;
           		using (Stream sourceStream = await storedfile.OpenStreamForReadAsync())
           		{
               		do
               		{
                   			int bytesread = await sourceStream.ReadAsync(buffer, 0, buffer.Length);
                   			_objNetStream.Write(buffer, (uint)bytesread);
                   			totalbytesread += bytesread;
                   			TransferedBytes = totalbytesread;

                   			if (args.nState != TransferState.FT_SEND_PROGRESS)
                   			{
                       				args.nState = TransferState.FT_SEND_PROGRESS;
                       				args.FileName = storedfile.Name;
                       				args.FileSize = (int)storedfileProperties.Size;
                       				args.DataBuffer = null;
                       				args.readbytes = 0;
                       				OnTransferUpdates(args);
                   			}
               		} while (totalbytesread < sourceStream.Length);
           		}
       	}

如要接收文件,需要实施 NetStream.Read() 事件回调,这已在“通信”部分进行了介绍。

readBytes = _objNetStream.Read(receivebuffer, (uint)bytesToRead);

最后,我希望该信息能够帮助你了解英特尔 CCF SDK,并希望你能够使用该 SDK 为 Windows 8 和 Android 开发出色的应用。

 

 

英特尔和 Intel 标识是英特尔在美国和/或其他国家的商标。

英特尔公司 © 2014 年版权所有。 所有权保留。

* 其他的名称和品牌可能是其他所有者的资产。

英特尔® 酷睿™ M 处理器

$
0
0

摘要

通过发布英特尔酷睿™ M 处理器家族的三个型号,英特尔正在推出第五代处理器的第一批产品(代号为 Broadwell)。 文本专为开发人员提供,将简要介绍这一 64 位多核 SOC 处理器,并概述可用的英特尔® 技术,其中包括英特尔® 高清显卡 5300。

英特尔酷睿 M 处理器的主要特性

英特尔酷睿™ M 处理器家族在更小的封装尺寸中提供了更出色的性能,降低了功耗和散热需求(非常适合轻薄的无风扇设计),并延长了电池续航时间。该处理器家族包含:

  • 英特尔高清显卡 5300 和英特尔® 无线显示技术 5.0
  • 英特尔无线 AC 7265 和(2015 年)支持 WiGig 的无线扩展坞
  • 英特尔® 智能音频技术
  • 英特尔® 平台保护技术和其他安全特性

尺寸减小 + 性能改进 = 功耗和散热需求降低

英特尔酷睿 M 处理器是第一款基于 14 纳米技术的处理器。 尽管晶体管的数量增加了 3 亿多个,但芯片尺寸仍减小了超过 30%。  英特尔酷睿 M 处理器的功耗更低,产生的热量更少。 2014 年第四季度发布的三款型号只有 4.5 瓦的功耗,这意味着它们可以无风扇运行!
这些型号在超薄(小于 9 毫米)设备中的性能尤为出色,包括平板电脑和二合一设备。


图 1: 小型低功耗英特尔酷睿 M 处理器的比较

图 1 中
左侧的图表显示,英特尔酷睿 M 处理器的散热设计功率
从 2010 年 的 18 瓦下降到了 4.5 瓦 。
它的功率在 4 年内降低了四倍,且比 2013 年降低了 60%

图 1 右侧显示了第四代英特尔® 酷睿™ 处理器与新的
英特尔酷睿 M 处理器的尺寸比较数据。
通过将封装体积减小约 50%,
英特尔将主板面积缩小了约 25%。

英特尔酷睿 M 处理器提供带 4MB 高速缓存的双核 CPU,所有尺寸均小于第四代英特尔酷睿处理器。 凭借英特尔® 超线程技术,四条线程可以同时运行。借助英特尔® 睿频加速技术 2.0,0.8 GHz 内核频率的处理器可达到 2.0 GHz,而 1.1 GHz 内核频率的英特尔酷睿 M 处理器 5Y70 可以达到 2.6 GHz。

 

由于 13 亿个晶体管在一个封装内提供 CPU、显卡、内存控制器、音频和连接,因此不会有任何性能损失。 事实上,与前一代英特尔® 酷睿™ 处理器 i5-4320Y 的对比测试结果表明,英特尔酷睿 M 处理器的性能有显著提升(见图 3)。

电源技术

在文本中,您将看到许多用于最大限度降低功耗的
英特尔技术。

  • 英特尔® 睿频加速技术 2.0 拥有能够计算处理器和显卡内核功耗的功耗监功能,以及能够提供封装功率控制设置,确保功耗和性能提升仅用于所需之处的功耗控制功能。
  • 支持 C 状态 C0、1、1E、3 和 6 至10 的增强型英特尔 SpeedStep® 技术可确保最低的闲置状态功耗。需要更高功率时,处理器会通过提高电压来执行快速转换。如果启用了超线程,转换会在线程级别进行。
  • 中断处理通过 X2 APIC 和 PAIR(电源感知中断路由)实现了功耗优化,可通过检查内核来避免唤醒深度睡眠状态的内核。

其他组件均具有改进的电源管理特性,下文的相应部分进行了介绍。

封装的其他部分

英特尔酷睿 M 封装与低功耗 PCH 共享一个芯片,后者具有智能功耗限制功能,支持 PCIe NAND、PCIe 2.0(x1、x2 或 x4 的 12 条通道),并添加了 2 个额外的 USB 2.0 端口。

集成式内存控制器支持英特尔® 快速内存访问和英特尔® Flex 内存访问技术,通过有条件的自刷新动态断电来节省功耗,并通过 4 种断电模式禁用未使用的系统内存,同时支持 DDR3L 或 LPDDR3 RAM(1600 或 1333)拆分为 2 条通道。

英特尔® 高清显卡 5300

作为英特尔高清显卡家族的新成员,英特尔高清显卡 5300 的起始基础频率为 100MHz,最大动态频率为 800MHZ(5Y70 为 850MHz)。  借助英特尔® 快速同步视频技术(面向媒体和视觉密集型应用的编码和后处理)、英特尔® InTru™  3D 技术、英特尔® 清晰视频高清技术和英特尔® 灵活显示接口(英特尔® FDI),英特尔高清显卡 5300 可支持 3 个显示器 (eDP/DP/HDMI)。 英特尔高清显卡 5300 采用该家族的 GT2 处理器(有 1.89 亿个晶体管),拥有 24 个着色单元、4 个 TMU、1 个支持 DirectX* 11.1+ 的 ROP、OpenGL* 4.2、OpenCLTM 2.0、Shader Model 5.0,同时通过 24Hz 的 HDMI 提供高达 (3840x2160) 的超高清分辨率。

 

 

 

 

 




测试结果显示,与前一代酷睿 i5 处理器相比,使用Cyberlink* MediaEsspresso* 转换高清视频的运行速度加快了 80%,游戏 (3DMark* IceStorm Unlimited v 1.2.) 运行速度加快了 40%。 除此之外,英特尔酷睿 M 处理器还可多提供 1.7 小时的电池续航时间(基于本地视频播放和 35WHr 电池)。

(所有测试均在搭载 4 GB 双通道 LPDDR3-1600 (2x2GB) 和运行 Windows 8.1 Update RTM 的英特尔 160GB 固态盘的英特尔参考平台上进行。 酷睿 M 使用 BIOS v80.1,而酷睿 i5-4302Y(前一代)使用 BIOS WTM137。 这两代处理器均使用英特尔® 高清显卡驱动程序 v. 15.36.3650,TDP 为 4.5 瓦。 其他设置: 系统电源管理策略: 平衡,无线: 启用并连接,电池大小假设: 35WHr。)

英特尔高清显卡 5300 具有以下特性,可提供额外的电池续航时间:

  • 英特尔® 显示节能技术(英特尔 DPST)6.0,可减少背光,提高对比度和亮度。
  • 英特尔® 自动显示亮度,可使用前面板的传感器来适应环境光线
  • 英特尔® 无缝显示刷新率技术(SDRRS 技术),可降低使用电池时的刷新率。
  • 英特尔® 快速内存电源管理(英特尔® RMPM),支持从低功耗状态进行自动内存刷新
  • 图形渲染 C 状态 (RC6),可在没有工作负载时将电源轨更改为低电压。
  • 英特尔® 智能 2D 显示技术(英特尔® S2DDT),可减少显示刷新的内存读取次数(仅在单管模式下使用,不用于 3D 应用)
  • 英特尔® 图形动态频率技术,可根据性能需求适时提高频率和电压

第二代 英特尔® 无线 AC7265 卡

英特尔酷睿 M 处理器家族还引入了更快速的
WLAN(性能提升 15-100%),同时通过使用 M.2 1216 外形,将体积减小了 70%。

与双频英特尔® 无线 A7260 相比,AC7265 提高了链路可靠性,扩大了覆盖范围,支持更多设备,并能够传输 1080p 视频,闲置状态下的功率降低了 50% (4mW),活动状态下的功率降低了 30%(web 浏览时为 8mW)。

注: 英特尔计划于 2015 年将支持 WiGig 的无线扩展坞引入英特尔酷睿 M 家族中。


英特尔®无线显示技术 5

这种新一代英特尔®无线显示技术(又称英特尔® WiDi)支持 1920x1080p@60fps
分辨率,可缩短连接时间(不到 6 秒)和游戏延迟(不到 65 毫秒)。 

技术包括:

  • HDCP 2.2
  • 自适应扩展和帧速率
  • 用于多点触摸屏或手势控制的 UoIP
  • 集成的英特尔® Update Manager,以简化驱动程序更新
  • 支持所有带游戏模式检测的 DX9/DX11 全屏游戏格式
  • 捆绑的英特尔 WiDi Remote 可实现双屏幕上的多窗口管理
  • 英特尔 Pro WiDi 中的更多特性,专门用于会议室:
  • DCM(不同的通道模式),
  • 隐私保护屏
  • WPAN 隔离
  • 可管理性

另请参见构建面向超极本TM的英特尔® WiDi 应用

英特尔® 智能音频技术

凭借 PCH 中更强大的全新集成式 DSP I2S,英特尔智能音频技术(英特尔® SST)可卸载主机 CPU 中的音频处理,从而降低平台功耗,并支持 MP3/AAC、Waves* 或 DTS* 后处理编码和语音唤醒。  英特尔 SST 必须使用 I2S 编解码器。

包括英特尔® 平台保护技术在内的安全性

搭载英特尔酷睿 M 处理器的系统具有增强的安全特性,包括:
  • 英特尔® 虚拟化技术(英特尔® VT-d 和支持 EPT 的英特尔® VT-x) - 优化虚拟机内存使用,支持 QoS 保证
  • 英特尔® 高级加密标准新指令(英特尔® AES-NI) - 6 个用于实现高性能安全性的英特尔 SSE 指令
  • 英特尔® 安全密钥  - 动态随机数字生成器
  • PCLMULQDQ(carry-less 乘法) - 通常用于加密
  • 操作系统保护
  • 病毒防护 (ND) 技术
  • SMEP(管理模式执行保护)和 SMAP(管理模式访问保护)
  • 带 Boot Guard 的英特尔® 设备保护技术
  • 英特尔® 主动管理技术 v10

注: 英特尔酷睿 M 处理器 5Y70 还支持英特尔博锐™ 技术、 英特尔® 可信执行技术(英特尔® TXT)和 Windows* Instant Go*(又称联网待机)。

开发人员建议


在开发面向英特尔酷睿 M 处理器家族的应用时,考虑以下特性和要求。

其他相关的英特尔文档和工具:

关于作者

Colleen Culbertson 是开发人员关系部门的平台应用工程师,负责在英特尔® 开发人员专区上撰写文章和一般博客。

性能测试和等级评定均使用特定的计算机系统和/或组件进行测量,这些测试反映了英特尔产品的大致性能。 任何系统硬件、软件的设计或配置的不同均可能影响实际性能。 购买者应进行多方咨询,以评估他们考虑购买的系统或组件的性能。 如欲了解有关性能测试和英特尔产品性能的更多信息,请访问:英特尔性能指标评测局限

英特尔有权随时更改产品的规格和描述而毋需发出通知。 

实现移动游戏的完美性能

$
0
0

下载文档

Codemasters GRID Autosport* 平板电脑优化和触摸部署

作者:Michael Coppock 和 Leigh Davies

 

移动游戏是一个巨大的市场。 预计显示,2016 年移动游戏将会急剧增长。 但是在低功耗的平板电脑和超极本™ 设备上,典型的移动游戏的发展远不及同一领域的 PC 游戏。 总部位于英国的游戏开发商 Codemasters 计划通过 GRID Autosport* 改变这一现状。 他们计划在带有直观的触摸控制的平板电脑中引进控制台级的显卡。

Codemasters 和英特尔的合作支持 GRID Autosport 充分利用整个第四代英特尔® 酷睿™ 处理器产品线,包括基于功率为 4 瓦的英特尔® 凌动™处理器的平板电脑。 位于英格兰 Southam Codemasters 总部的高级编程师 Richard Kettlewell 表示:“我们应该迎合整个市场。 我们确保了游戏拥有全面的显卡选项,从而能够扩展到高端产品,但是如果您使用的是平板电脑,它也能够很好地运行。”

本文介绍了 Codemasters 团队如何针对平板电脑对 GRID Autosport 进行优化, 如何利用他们的聪明才智让 GRID Autosport 在基于 4 瓦的英特尔凌动处理器上完美显示并提供几年前在出色的 PC 上无法实现的视觉体验, 并同时在高端硬件(如基于锐炬™ 显卡的超极本或 PC)上提供大量增强特性,具体见上一篇文章: 占据有利地位: Codemasters 借助 GRID Autosport* 在电脑向平板电脑的优化中占据领先地位。 难以实现的地方在于在密集的前端 UI 中添加触摸控制的同时确保在平板电脑、超极本和 PC 上实现无缝体验。

针对平板电脑进行优化

GRID Autosport* 中的显卡引擎是从 GRID 2 引擎演进而来。 它面向第四代英特尔酷睿处理器密集优化(通常在超极本中)。 GRID 2* 旨在以中等设置在第四代英特尔酷睿处理器的英特尔® 显卡上运行,其性能堪与 Playstation* 3 和 Xbox 360* 比肩。 在 15 瓦的超极本上,分辨率为 1366x768 的游戏性能稳定在 30FPS。 除了面向高端游戏 PC 的高质量设置之外,GRID 2 还可提供多种质量较低的设置。 这可以确保最大限度地在旧版硬件上兼容。 为了确保 GRID 2 与多种版本和功耗较低的 GPU 兼容,Codemasters 降低了现有效果的质量设置,如阴影分辨率。 此外,还禁用了一些后处理特性,包括人群、车手模型以及 GRID 2 体验中不必要的粒子效果(图 1)。


图 1:在 GRID 2 的低质量设置中禁用了人群、车手模型和粒子效果等特性。

为了使 GRID Autosport 与采用超低压英特尔凌动处理器的平板电脑兼容,我们将这些低质量的设置作为起点。 最初的测试并不理想。 使用 GRID Autosport 的内置基准测试以及最初禁用了人群、车手和粒子的超低设置,游戏的运行速度低于 20FPS。 一个典型的帧需要 53ms 进行渲染,远远超出预期的 30ms。 具体观察帧将可了解哪一项渲染的耗时最长(图 2)。


图 2: 左侧是超低质量设置下 GRID Autosport* 中的一帧。
右侧展示了预优化的渲染时间(按特性划分,单位:ms)。

很明显,传统的方法没有效果。 仅通过扩展模型纹理、创建过多的 LOD 和删除几何无法实现要求的 30FPS。 删除一些效果(如后处理中的复杂景深和运动模糊)意味着许多做重复工作的像素着色器可以删除。 删除后,同时还取消了其随附的速度/深度预计算 (pre-pass) 要求。 删除速度/深度预计算 (pre-pass) 尤其重要,因为它能够减少 ~30% 的每帧绘制调用数,并减少 ~25% 的渲染工作负载。 工作室希望避免为游戏中的每个对象写入新的着色器版本,因此他们想要为平板电脑快速创建一个更简单的渲染通道模型。

幸运的是,动态汽车环境立方图通道中使用了简单的着色器版本。 该立方图通道甚至没有在超低设置中使用,因为禁用了动态反射。 Codemasters 选择在新的平板电脑模式中使用这些着色器。 由于该通道是针对立方图而设计,所以它无法读取屏幕空间映射。 因此,平板电脑版本将没有车下的阴影、SSAO、动态阴影、夜晚的汽车车头灯以及其他一些图形特性。 虽然需要对其中一些进行更换,但是多数还是能够在平板电脑上运行。 图 3 展示了最早使用基本立方图着色器的游戏的图片。


图 3:早期使用基本立方图着色器的图片

虽然某些位置过于简单,但是它将每帧速度提升了 20ms 以上,几乎达到性能目标。 为了修复仍然需要屏幕空间映射的着色器,如车下阴影和夜晚轨道上汽车车头灯,我们添加了新的渲染器通道。 新的渲染通道用作环境贴图通道的覆盖层。 它支持仅针对特定项(如车道、显著减少绘制调用数量和相关渲染)创建所需信息(如速度/深度通道)。

除了显著提升性能以外,很显然,新的渲染器是一个有价值的调试工具。 能够具体分析环境贴图着色器而非仅在汽车反射中使用它们,将会显示出许多较小的视觉缺陷和低效现象。 一些着色器读取无效的屏幕空间映射,因而执行的计算昂贵且对反射无效。 此外,光线出现不连贯的现象,但是该问题被着色器所遮盖。 修复这些问题会为平板电脑带来出色的渲染解决方案。 它还改进了为反射使用这些着色器的高端系统的质量和性能。

此外,还带来额外的改进 — 渲染场景的内存带宽需求显著降低。 另外,还有一些其他较小的改进。 billboard 系统最初没有在透明项目上使用像素着色器中的 discard,而依赖于将 alpha 值设置为 0 在场景中混合。 仅当更新深度缓冲器时禁用颜色渲染目标,而非使用 0 alpha 混合,将可节省更多带宽。

平板电脑着色器视觉质量改进的另一个方面是选择性地使用高频率细节,如镜面贴图。 在屏幕较大的台式机系统上,精细的每像素效果(如法线图和高反射材料)的视觉质量将会有很大差别。 在屏幕尺寸较小的设备上,这些高频率细节的影响较小。 为了节省内存带宽,多数用于平板电脑设置的着色器应使用能够影响大面积屏幕,而非高频率细节的效果。 但是有一些例外,如向车轮添加镜面高光,为车体添加特殊的“金属镜面”(图 4)。


图 4: 车轮镜面高光和汽车的特殊“金属镜面”示例

Codemasters 的主要目标是实现处理功耗和最佳视觉效果的完美平衡。 鉴于此,Codemasters 评估了烟雾计算。 最初,它们以顶点为单位来实现,其中包括 1 个pow、1 个exp、多个 lerps、 2 个 normalize 和 1 个 sqrt函数。 删除它们并简化运算可以节省带宽和时间,这适用于游戏的其他位置。

平板电脑优化完成后,GRID Autosport 的性能超过最初的 30FPS 的目标。 节省的性能允许 Codemasters 添加之前在低质量设置中没有进行渲染的特性。 例如,将人群重新添加回去,但是使用的是简单的 billboard 系统而非完整的 3D 模型。 此外,还放回车内司机和粒子系统。 最终结果可在图 5 中查看。


图 5:在上方的图片中,将司机模型放回平板电脑版本。
在下方的图片中,您可以看到优化后的性能提升。

升级问题

许多游戏在进行升级以适应其他场景部分之前会在低分辨率平面中进行大量重绘(如粒子效果)来渲染系统。 Autosport 也不例外,它为电脑和控制台的粒子效果使用低分辨率平面。 在主流 PC、PlayStation 3 和 Xbox 360 上,创建尺寸较小的深度缓冲器用于粒子系统,然后将生成的粒子效果升级回全尺寸并与主场景相组合的成本可以忽略不计。 平板电脑有望继续保持该性能优势。 但是在平板电脑上,Codemasters 发现创建尺寸较小的深度缓冲器和升级的固定成本是 3.5ms,将绘制粒子前的帧速率降低 10%。 当汽车偏离轨道时,该游戏只能生成大量低分辨率粒子。 Codemasters 决定不支出该高昂成本, 而减少离子的数量,从而获得最佳的总体效果。


图 6:轨道较少使用粒子效果。

另一项实验是使用控制台标题上常用的技术来改进性能。 3D 场景以低分辨率渲染,然后在添加 HUD 之前升级至全分辨率。 初次测试非常成功,但是随着优化的场景渲染越多,通过升级而实现的优势便越少。 所有优化完成后,以标准的后台缓冲区分辨率渲染游戏将比运用升级固定成本快。

优化结果

图 7 是以芝加哥为背景的起始线,该场景在 GRID2 和 GRID Autosport 中非常常见,图为面向平板电脑使用的超低设置。 不同的游戏中城市设计稍有不同,因此无法进行确切地比较。 但是能够看到他们的一些权衡和添加的特性。 添加的特性包括粒子和人群,这在 Autosport 中很明显。


图 7: 左帧是取自超低设置下的 GRID Autosport*。 右帧取自 GRID 2。
两帧都是以芝加哥为背景的起始线。

GRID Autosport 分别在 18 个渲染目标上使用 820 个绘制调用进行渲染。 GRID 2 需要分别在 49 个渲染目标上使用 1617 个绘制调用。 GPU 内存读取从每帧 122Mb 下降到 53Mb。 定点和像素渲染器调用分别从 736K 和 9.48M 下降到 336K 和 4.17M — 即使添加了人群和粒子系统。 最终结果是渲染图像的速度提高近 2 倍(仅有微小差别),且能够渲染更多原始内容。

添加触控功能

拥有在平板电脑上运行的性能只是其中的一部分。 GRID Autosport 来自 PC 和控制台。 它主要围绕使用游戏控制器、键盘/鼠标和驾驶外设而设计。 这些选项均不适用于平板电脑。 幸运的是,Codemasters 拥有开发平板电脑游戏的经验,它曾创建过基于 iOS* 的 F1 Race Stars*。 因此对于 GRID Autosport,Codemasters 添加了一个带有用于驾驶和控制的模拟区域的触控层(图 8)。


图 8: GRID Autosport* 中的触控层支持驾驶和加速操作。

此外,还添加了面向暂停、摄像头和重赛模式的触摸控制。 当手指接触屏幕时,将会显示所有触摸控制,这可为用户提供重要的视觉反馈。 为了在用户驾驶时提供一进步帮助,还提供了许多驾驶协助,这些协助在触摸模式中将会默认启用(图 9)。


图 9:使用触摸控制时可用的驾驶员协助模式

前端的挑战更大。 它是一个大型的状态设备,也就是说游戏能够随时知道目前选中了哪个控制以及用户可以将哪些控制移至下一步。 此外,屏幕上的信息也非常密集,尤其是汽车和比赛设置界面(图 10)。


图 10:
设计中密集的菜单系统无法在平板电脑上使用。

开发人员很早就清楚,不可能使这些界面上的所有元素都支持触控。 即使技术上可行,在小尺寸的平板电脑设备上,这些元素的距离将会过于紧凑。 不可改变的是,控制元素之间的建议距离是 7mm,但是实际上至少是 2mm,这些项目距离太近。 Codemasters 不希望更改游戏的外观和感受,或将界面简化为不包含定制选项。 因此,他们使用了另一种设计 — 在前端界面上添加虚拟游戏控制器。


图 11:
添加了虚拟游戏控制器,以便玩家轻松导航密集的菜单系统。

现在,针对 TV 或 PC 的 10ft 显示器而设计的前端也可在 7in 的平板电脑上使用。 此外,使用游戏控制器快捷键访问特性的工具提示转换为界面底部的触摸控制(图 12)。


图 12:
向前端添加快捷键以便更轻松地导航。

在触摸模式下,添加了一些之前没有的工具提示,以便用户访问最常用的游戏模式。

在 2 合 1 设备上集成该体验

前端 UI 的显示有所不同,具体取决于是否运行键盘、游戏控制器或触摸功能,每种控制方法有不同的工具提示(图 13)。


图 13:
左侧展示了在键盘上玩游戏的界面。
右侧是使用虚拟游戏控制器的触摸界面。

接下来,Codemasters 面临的问题是,如果用户在 2 合 1 设备或可拆卸系统(如 ASUS T100*)上运行时应该如何处理。 如果用户一开始使用了键盘,但是在游戏期间键盘无法使用,用户如何与游戏继续交互? 解决方案需要做出几处变更:首先,当设备从一种模式更改为另一种模式时,集成了 Windows* API 调用的游戏将可通知系统。 当 Windows 检测到 lParam 中带有 “ConvertibleSlateMode” 字符串的更改平板模式时,将会发送 WM_SETTINGCHANGE消息。 在发生扩展坞模式变化的情况下,它会使用“SystemDockMode”字符串广播相同的讯息。 用于查询当前状态的 API 是 GetSystemMetrics(图 14)。


	case WM_CHANGESETTING:
	if (wcscmp(TEXT(“ConvertibleStateMode”), (TCHAR*) lParam)==0)
		NotifySlateChangeMode();
	break;


图 14: 代码版权所有 © 2014 英特尔公司。 根据英特尔示例源代码许可的要求进行分发。

 

当系统运行在全新的 Windows 8 UI 模式下,该方法可奏效。 BOOL bSlateMode = (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0).

该解决方案可行,但是可能会出现两个弊端。 并非所有的设备都支持 API,即游戏可能会收不到 WM_CHANGESETTING 消息,而且调用 GetSystemMetrics 可能会不考虑设备的实际状态而返回一个任意值。 其次,用户可能在蛤壳式超极本上运行,并希望从键盘转换为触摸,而不实际更改模式。

两个问题的解决方案非常简单:游戏能够记忆当前正在使用的控制器。 如要正确显示各种工具提示和触摸层,这是有必要的。 在 Windows 消息循环中,如果收到 WM_TOUCH 或 WM_KEYDOWN 消息,游戏仅检查设备的当前类型;如果使用了不同的设备,将会触发模式更改。 GRID Autosport 可以根据用户首选的输入设备来转换控制,而且仅在收到 WM_CHANGESETTING 消息时调用 GetSystemMetrics 可以确保 API 正确部署。

Codemasters 向 GRID Autosport 添加触摸层还有最后一个问题。 游戏中有几处用户无法交互的过场动画。 在显示着触摸层时,它会让用户感觉能够与其进行交互。 为了避免产生混乱,不带来挫败感,在过场动画中删除了触摸层。

完美游戏体验

Codemasters 在面向平板电脑优化 GRID Autosport 时面临许多挑战。 传统的办法无法解决问题, 因而需要更有创造性的解决方案。 GRID Autosport 在基于 4 瓦的英特尔凌动处理器的平板电脑和基于高端锐炬显卡的超极本或 PC 上都能够提供完美体验。 创新的触摸控制支持针对 TV 和大型显示器设计的前端在较小的 8 英寸的平板电脑屏幕上运行。

移动游戏市场可能比传统 PC 和控制台市场更大,而且它还在不断增长。 平板电脑和低功耗超极本用户为何还需要为便携性而降低质量? Codemasters 的回答是他们不需要;玩家可以获得高质量的移动游戏体验 — 尤其是多功能的第四代英特尔酷睿处理器产品,包括基于 4 瓦英特尔凌动处理器的平板电脑。

参考资料和相关链接

相关英特尔链接:

企业品牌识别 http://intelbrandcenter.tagworldwide.com/frames.cfm

英特尔产品名称 http://www.intel.cn/content/www/cn/zh/processors/processor-numbers.html

作者介绍

Michael Coppock致力于 PC 游戏性能和显卡领域,自 1994 年以来一直任职于英特尔。 他负责帮助游戏公司充分发掘英特尔 GPU 和 CPU。 他主要关注硬件和软件,曾负责过许多英特尔产品,最早可追溯到 486DX4 Overdrive 处理器。

Leigh Davies已在英特尔工作了十年,主要致力于游戏和显卡领域,并与许多领先的欧洲 PC 开发人员有着密切合作。 在加入英特尔之前,他曾在以及总部位于英国的公司担任高级图形程序员,负责开发 PC 和控制台标题。

SensiGator 为在 Windows* 8 平板电脑上使用必应*地图开启新篇章

$
0
0

下载 PDF

作者:Geoff Arnold

倾斜平板电脑已经取代旋转的地球仪,成为学习地理的一种途径。SensiGator英特尔® 应用创新大赛 (AIC 2013)的教育类别冠军,其设计在一定程度上拓展了基础地理学生的想象力。SensiGator 适用于 联想 ThinkPad* Tablet 22 合 1 超极本™(运行 Windows* 8.1),充分利用了平板电脑平台的各种传感器和输入模式的优势,包括 10.1 英寸高清触摸屏和用于连接键盘和显示器等外设的多种选项(蓝牙*、USB 和 mini-HDMI*)。这些外设很重要,因为 SensiGator 应用的开发者 Bryan Brown 在他的程序员生涯中,首次完全在平板上完成了开发和测试工作。他在报告中表示正因为英特尔® 凌动™ 处理器(双核 4 线程,高达 1.80 GHZ)的支持,构建工作的速度与在高端电脑上相差无几。

Brown 以他的 BlinkTalk应用赢得了 2012 年度英特尔应用创新大赛的冠军。对他而言,SensiGator 带来了全新的编程挑战,包括如何将 Windows 运行时(又称 WinRT) API 应用于 Windows 8 桌面应用,如何在触摸屏上模拟键盘和鼠标操作,以及为了提供流畅的用户体验,如何仅使用机载传感器(尤其是测斜仪和陀螺测试仪)导航地图。


视频 1:SensiGator 提交的 2013 年度英特尔应用创新大赛视频,
说明了 SensiGator 通过传感器实现的必应地图导航。

 

充分利用平板电脑的屏幕和传感器

ThinkPad Tablet 2 的 10.1 英寸高清屏幕能够完美呈现必应* 地图。该设想是为用户呈现从飞机窗口俯瞰地球的图像,增强内容包括带有预期标签的高速公路网络、干道和城镇(本例中由必应提供)。当用户将平板电脑右侧向下倾斜时,倾斜仪检测到该倾斜,他/她似乎正在向东飞行。景象能够平滑滚动,这很大程度上是因为平板电脑的处理能力支持快速渲染图像。(Microsoft 的必应地图倾斜系统能够支持多种不同级别的地图细节预渲染,然后将每一张地图切割成贴片,以便快速提取和显示,因此也是实现平滑响应的重要因素。)

放大只需沿顺时针方向快速扭转平板电脑。 一旦陀螺仪检测到大于 150 度/秒的角速度,地图上的小项目便会随着图像放大在屏幕上清晰呈现(见图 1)。 轻敲相反方向即可缩小图像,直到屏幕仅显示大洲级别的细节(见图 2)。


图 1:使用 SensiGator 放大必应地图


图 2:使用 SensiGator 呈现大洲级别解析度的必应地图

轻触屏幕上的按钮即可在地图上居中显示用户在地球上的位置;这一功能使用来自地理定位传感器的数据(见图 3)。SensiGator 具有半透明的平视显示器,在屏幕上提供了用于触摸导航的按钮,并显示屏幕上地图的中央点和用户实际位置的精确经纬度信息(见图 4)。平板电脑的手写笔可以用于插入虚拟图钉。联想平板电脑具备多个端口,可以通过 USB 或 mini-HDMI 连接外部显示器、键盘和鼠标。Brown 认为,除了在教室里快速旋转地球仪和想象地球上的居民抱着可爱小生命的乐趣,从用户体验的角度而言,SensiGator 可以完胜历史可以追溯到公元前三世纪的老式地球仪


图 3:现在的洛杉矶地区的 SensiGator 屏幕截图


图 4: SensiGator 平视显示器

 

调整默认的多点触控功能,确保良好的用户体验

创作儿童能够轻松使用的东西本身就非常困难。比赛规则也非常棘手,参赛者必须创作 Windows 8 桌面应用,因此对 Brown 而言,使用 Bing Maps Windows Presentation Foundation (WPF) SDK比使用 Windows 商店应用的必应地图更加明智。

“这个过程存在一些挑战,主要是因为在 Windows 8 桌面应用中使用 WPF SDK 时发现一些异常行为。 这种行为在使用按压手势执行缩放等多点触控操作时尤为明显”, Brown 在 2013 年 8 月向大赛评委介绍 SensiGator 的 CodeProject* 文章中写道。

在详细浏览 Microsoft 开发人员网络 (MSDN) 论坛中关于这个问题的讨论后,Brown 决定改写必应地图的默认行为,使用 TouchDown 事件禁用多点触控和触控缩放控制。片段 1 中的代码片段显示了工作原理:


private void Map_TouchDown(object sender, TouchEventArgs e)
{
   e.Handled = true;
}


片段 1:改写必应地图默认的多点触控功能

 

Brown 将 SensiGator 构建为 C#/WPF 应用,使用了 Visual Studio* 2012。这也是首个支持 .NET 4.5 的 Visual Studio 版本。他在英特尔® 开发人员专区中阅读到一篇有关 Windows 8 WinRT API 的文章,了解到 Visual Studio 2012 在默认情况下无法从常规桌面 C# 项目访问 WinRT;开发人员首先需要声明他/她的项目针对 Windows 8。Brown 指出:“完成这一步后,就可以引用访问传感器数据所需的 Windows.Devices.SensorsWindows.Devices.Geolocation程序集。”

SensiGator 应用引用了 SensorHub 类库,Brown 创建这个库的目的是用于包装 Windows.Devices.Sensors 和 Windows.Devices.Geolocation 命名空间 API。SensorClass 对象在主应用中实例化,用于访问平板电脑传感器数据并生成三个连续线程,用于数据处理、用户界面互动(使用 Dispatcher.BeginInvoke)和获取地理位置信息。数据处理和 UI 线程的更新间隔为 50 毫秒,地理位置线程的更新间隔为 5 秒。

Brown 表示:“我最初想在主应用层实例化 GeoLocator 对象,并订阅用于处理位置变化事件的事件处理程序,但我最终决定使用 GetGeopositionAsync(),并采用公共方法将其包装在我的 SensorClass 对象中。这就是为什么在一个线程中轮询地理位置信息而不采用事件驱动的原因,但是,由于轮询率是五秒钟,用户的可辨别地理位置没有迅速改变,因此开销最小。”


图 5: SensiGator 架构概述

 

模拟键盘和鼠标操作

对于缩放和导航按钮,Brown 想复制键盘操作,因此他使用了 Windows Input Simulator DLL,这是一款用于模拟键盘和鼠标操作的 C# SendInput 包装程序。

Brown 使用了第三方开源 InputSimulator DLL执行一些常规导航,从而提供一种轻松访问 Win32* SendInput 方法的途径。 引用 InputSimulator DLL 并将 WindowsInput 命名空间添加到项目后,他就能够调用需要使用各种虚拟键码(ADD、SUBTRACT、LEFT、RIGHT 等)作为参数的 SimulateKeyPress 方法。针对地图缩放,他创建了一个 ZoomIn() 方法,当平板电脑在 Z 轴上的角速度超过 150 度/秒以及用户轻触放大导航按钮时将调用此方法(见片段 2)。


private void btnZoomIn_Click(object sender, RoutedEventArgs e)
{
   if (myMap.ZoomLevel < ZOOM_MAX)
   {
  	myMap.Focus();
  	ZoomIn();
   }
}
.
.
.
public void ZoomIn()
{
   InputSimulator.SimulateKeyPress(VirtualKeyCode.ADD);
}

片段 2:通过屏幕上的按钮启用放大功能的代码

 

Brown 早在 2013 年度应用创新大赛之前就在研究必应地图。他的 NuiMaps应用是他参加英特尔® 感知计算挑战赛的四款应用之一,于 2013 年底完成。在对必应地图控件的早期研究工作中,他调用了 InputSimulator 的 SimulateKeyPress 方法,用于导航东西南北方向(例如:"InputSimulator.SimulateKeyPress(VirtualKeyCode.RIGHT)")。这种方法的优势是,通过键盘的方向键执行导航时必应地图控件能够自动调节缩放级别分辨率。(请参阅 MSDN 文章“了解缩放和分辨率”,了解有关缩放级别分辨率的详细信息。)

Brown 说道:“这个方法的缺点是当模拟多次快速按键时出现运动震荡。在 SensiGator 中,我想让动态更加流畅,因此没有模拟击键,而是推导出一个非线性方程,用于控制不同地图缩放级别的转换速度,并通过在屏幕上重新将地图居中实现导航。”片段 3 中显示了工作原理。


cf = Sensefactor / Math.Pow(10, (myMap.ZoomLevel * 0.25 + 0.5));
.
.
myMap.Center = new Location(myMap.Center.Latitude + cf,
            	        	  myMap.Center.Longitude);


片段 3:控制不同地图缩放级别的转换速度

 

传感器导航面板包含一个通过传感器数据导航时可用于增减地图行进速度的灵敏度滑块。图 8 中显示的居中函数 (cf) 使用该滑块的值(即:Sensefactor = sliderSense.Value)。Brown 在注释中说明,他的方程并未采用上文提及的 MSDN 文章中的信息,而是从经验数据推导得出。

哪一端朝上?(解决朝向问题)

另一个挑战是检测平板电脑是横向还是纵向,然后相应地处理地图导航。SensiGator 用于在平板电脑横向正面朝上时操作,但在纵向上也能正常工作。然而,当平板电脑的方向改变时,应用需要重新定义如何使用平板电脑的倾斜仪数据执行地图导航。片段 4 中的代码片段表明了 Brown 的应用如何首先检测平板电脑的朝向,然后再重新定义 X 轴和 Y 轴。


LocationRect bounds = myMap.BoundingRectangle;
MapWidth = bounds.Width;
MapHeight = bounds.Height;
.
.
.
if (MapHeight > MapWidth)
{
   lblOrientation.Content = "Portrait Orientation";
   XAxis = -Pitch;
   YAxis = Roll;
}
else
{
   lblOrientation.Content = "Landscape Orientation";
   XAxis = Roll;
   YAxis = Pitch;
}

片段 4:如果平板电脑的朝向发生了变化,重新定义 X 轴和 Y 轴

 

Brown 在平板电脑上完成了所有代码编辑工作,能够更加轻松地测试各种功能,“平板电脑是消费的最佳选择,但不适合创作内容”的传统观点并不完全正确。他说,不必为了测试将应用下载到平板电脑上,这可能促进了他能够在六周内完成该应用。这种体验也不是没有缺点:例如,构建过程比在开发级别的计算机上消耗更多时间。

Brown 说道,如果他要开发另一款代码不是太多的应用,将再次尝试在平板电脑上开发,虽然他也会考虑可能支持脱离平板电脑工作的集成开发环境。他说,重点在于寻找到一款包含所有传感器、并且能够在桌面运行的优秀的 Windows 平板电脑模拟器,就像用于构建平板电脑、手机 Android* 和 iOS* 应用的模拟器一样。

Brown 是一名拥有多年经验的专业人员,他承认:“涉及到 Visual Studio,我并不确定目前在哪能找到工具,也不知道是否存在适当的模拟器环境。”这一言论本身暗示了在 Windows 8 平板电脑和触摸屏上进行开发的广泛可能性。

像所有开发人员一样,尤其是那些受到紧迫的比赛日程限制的开发人员,Brown 能够列出几个如果有更多时间他想尝试实施的功能。目前,SensiGator 仍局限于必应地图的航测视图;他将来想试验道路和鸟瞰视图。在今年的世界移动通信大会上,Brown 在英特尔的展位上作为嘉宾演示了 SensiGator,一名观众建议平板电脑的倾角越大,地图滑过的速度应越快。

关于 Bryan Brown

20 多年来,Bryan Brown曾在多家位于洛杉矶地区的公司担任软件工程师。他目前在一家制造光谱和色谱设备的公司就职。他利用晚上和周末免费编写代码,经常研究关乎人类福祉的软件。他的工作非常重要,为他在 2012 年创立的“人机技术”非营利组织提供着支持。

2013 年度应用创新大赛的关注者可能会认为 Brown 在业余编码爱好者之间一鸣惊人,也许 SensiGator的成功是凭借几分幸运。 然而,Brown 的成功并非昙花一现。 他早期的BlinkTalk应用为患有眼部下方随意肌麻痹的闭锁综合征患者提供了语言交流的途径。 Brown 还凭借他的 NuiLogix 项目(用于网络设备控制的感知计算实例)在 2013 年度英特尔感知计算挑战赛第一轮中获得了二等奖。

他的另一个项目 PerC 机器人手臂控制器获得了英特尔感知计算挑战赛第二轮的先锋奖。(Brown 的视频机器人手臂响应语音命令执行拾取、移动、并将棋子投入玻璃杯;能够调出美味鸡尾酒或照顾孩子的机器人将为期不远。)由于对 Brown 和他的应用印象深刻,英特尔为 Brown 提供了 2014 世界移动通信大会的参展证,让他在英特尔的展位上演示 SensiGator。

与 Brown 的谈话让人想起 10,000 小时定律(Malcolm Gladwell 在他的书《异类》(Outliers)中着重强调了这一定律,引用自 2008 年 10 月出版的《纽约客》)。该规则的要点:要成为某个领域的专家,需要大约 10,000 小时的练习。Gladwell 指出,大多数看似一鸣惊人的天才都在出名之前经过多年努力。

Gladwell 的观察指出除了投入时间的重要性外,积极应对变化的能力对于在任意领域取得成功同样非常重要,包括编写代码。Brown 对想向他学习的开发人员提出了以下赠言:

“我建议,永远不要把自己锁定在一个特定的语言、平台或工具,不要试图使用相同的技能组合解决每一个问题。这项大赛中最有趣的部分就是要求开发一款在 Windows 8 平板电脑上使用的 Windows 桌面应用。这可能会让倾向于原生 Windows 8 应用开发方法的开发人员措手不及,但其中的乐趣就是超越你的舒适区,并终将获得回报。”

资料来源

英特尔能够帮助开发人员解决像 Brown 一样的问题,充分利用最新版 Windows 8 和英特尔技术的优势,构建跨多种设备的灵活创新的应用。英特尔开发人员专区提供了适用于跨平台和桌面的世界一流的知识、工具和 Windows 8 应用支持。Brown 在工作过程中便从这里获得了丰富信息英特尔开发人员专区能够为像 Brown 一样有志于创作支持多种输入方式(触摸/手写笔以及键盘/鼠标)的二合一应用的开发人员,提供重要帮助。

Brown 还利用了以下资源:

  • Windows Input Simulator,用于模拟键盘和鼠标的开源 C# SendInput 包装程序
  • “多点触控产生的异常跳跃行为 (WPF)”,有关处理桌面必应地图的多点触控收缩和缩放手势漏洞的 MSDN 论坛讨论

相关文章

面向超便携设备的触控开发人员指南https://software.intel.com/zh-cn/articles/ultrabook-device-and-tablet-windows-touch-developer-guide

超极本和平板电脑 Windows* 8 传感器开发指南https://software.intel.com/zh-cn/articles/ultrabook-and-tablet-windows-8-sensors-development-guide

触摸屏和传感器https://software.intel.com/zh-cn/touch-and-sensors

CSDN专访:聚焦英特尔® 实感™ 技术开发套件

$
0
0

转载自CSDN,点击此处查看原文。

英特尔® 实感™ 技术集手势识别、3D脸部识别、3D增强现实等功能于一身。今年10月,英特尔发布了基于Windows 8操作系统的Intel® RealSense™ SDK Gold版。为了进一步了解其中的开发要诀,CSDN采访了英特尔软件与解决方案事业部合作伙伴关系部在中国的技术支持团队。

 

体感技术作为未来人机交互的新形式,得到了科技巨头的普遍重视,无论是微软的Kinect,还是谷歌的研究项目Tango,都希望在人机交互上获得突破式创新,引领用户体验变革。在这些技术中,英特尔® 实感™ 技术(Intel® RealSense)也是是需要重点关注的技术之一。

英特尔® 实感™ 技术提供了业界第一款且是尺寸最小的PC端集成式前置3D摄像头,并提供了软件开发工具包 (Intel® RealSense™ SDK,简称SDK)。它的功能强大,RGB分辨率为1080P,深度分辨率达到VGA,功能上囊括了手势识别、3D脸部识别、3D增强现实、语音识别、Unity工具集、物体追踪、表情侦测、背景移除、浏览器支持等。功能与性能都为业界领先。

今年年底,随着集成有英特尔® 实感™ 摄像头的一体机和超极本的上市,用户可以亲身体验由英特尔® 实感™ 技术带来的全新人机互动。作为行业的技术先锋之一,英特尔在硬件创新的同时,积极推动软件应用的开发并培育生态系统,力求在产品上市的第一时间,能够有丰富的软件应用供用户使用。为此,英特尔亦设立了强大的技术支持团队帮助ISV和独立开发者的开发工作。

我们曾在8月对英特尔® 实感™ 技术支持团队做了一期《近匠》专访,为了进一步了解英特尔® 实感技术,以及软件开发过程中的技术支持模式,我们采访了英特尔® 实感™ 技术支持团队,以及从2012年底便开始接触英特尔® 实感™ 技术的广州同声科技团队。

CSDN请问今年10月发布的 SDK都集成了哪些功能?它是否可以向后兼容2013年的Creative Senz3D* 摄像头?

实感技术支持团队:10月英特尔发布了基于Windows 8操作系统的Intel® RealSense™ SDK Gold版,供开发者下载使用。该版本SDK集成了手势识别、3D脸部识别、3D增强现实、语音识别、Unity工具集、物体追踪、表情侦测、背景移除、浏览器支持等功能。相较于9月发布的Beta版,该Gold版的功能性与稳定性都得到了极大的提升。

由于2014实感摄像头与2013 Creative Senz3D*摄像头的硬件差异较大,新版本的 SDK 只支持2014实感摄像头,并不支持2013 Creative Senz3D* 摄像头。对于手头没有集成了实感摄像头设备的开发者,英特尔还提供相应的外置开发摄像头以供调试,并在SDK介绍网页可以找到相应的订购链接。

CSDN 请问实感技术可以实现3D手势识别么?相对于市面上的一些类似解决方案,优势在哪儿?具体为开发者提供了哪些功能?

实感技术支持团队:英特尔® 实感™ 技术的手势识别基于二维图像与深度信息的准确映射,为开发者提供高精度3D识别。英特尔® 实感™ 技术的手势识别可覆盖人手的22个关节点,并且支持双手识别,因此PC端的手势控制辨识准确,操控性好。为了方便开发者,SDK还预先定义了常用手势,如胜利V手势、OK手势、竖大拇指、握拳、手掌张开、再见、挥手等。此外手势识别还提供轮廓模式(contour mode),这一模式下,CPU利用率大幅降低,可满足低功耗需求。

CSDN请问3D脸部识别功能与传统的2D脸部识别相比,能力有哪些提升?

实感技术支持团队:英特尔® 实感™ 技术的3D脸部识别,精确度与可靠性优于2D脸部识别。2D脸部识别基于2D平面图像特征点辨识,普通的照片也可能蒙混过关。然而3D脸部识别由于在2D平面图像的基础上增加了对深度信息的计算分析,辨识复杂度提升的同时可靠性也获得增强。只有当用户本人出现在摄像头前才能通过辨识,二维图片则无法蒙混过关。

英特尔® 实感™ 技术支持78个脸部特征点,即使脸部被部分遮蔽或头部偏转,也可以准确识别。

脸部识别演示(普通状态与部分遮挡)

 

CSDN请问您认为3D脸部识别功能,在PC端和移动端均有哪些应用场景?还可以与哪些设备已有的功能进行结合?

实感技术支持团队:借助3D脸部识别,一些传统的线上线下服务将会更加安全可靠,用户体验也更人性化及定制化。

比如,随着网络安全形势恶化,在线网站的账号密码规则越来越复杂,使得用户难以记住。3D脸部识别可以减轻网站及用户对账号密码的依赖,令身份验证过程更轻松简捷。3D脸部识别可以获知用户的个性化特征,如年龄、性别、表情等,并可根据这些特征做针对性的内容推送或定制化服务。

3D脸部识别还可与手势、语音、指纹等功能结合,进一步提升安全性与用户辨识度。相信在不久的未来,脸部识别作为新的用户身份标识,将改善互联网服务的身份验证环节。

 

CSDNRealSense SDK集成了MetaioAR技术,现在AR技术的难点和AR应用的开发难点在于什么?另一方面,对于开发者来说,这个AR应用的市场前景如何?

实感技术支持团队:增强现实(Augmented Reality,简称AR)技术的难点在于对物体、图像的辨识与追踪,尤其是无标签(markerless)的辨识与追踪。市面上的一些AR技术多基于标签辨识,开发者需要设置特定的标签作为辨识点,这样虽然降低了技术难度,但实际性能与用户体验却不甚理想。英特尔® 实感™ 技术提供3D/2D无标签的AR功能,可降低开发的技术门槛与工作量。AR应用的开发难点在于应用的创意与互动体验创新。如何令虚拟与现实完美结合,如何设计流畅、自然的应用场景,将是开发者的着力点。

AR应用未来在浸入式协作应用模式方面拥有广阔市场,尤其是游戏、教育、娱乐等领域。目前,Qualcomm、谷歌等科技巨头均发力于AR技术,可以预见AR技术与创意应用将呈现爆发式发展势头,改变PC与移动设备上的互动场景,丰富用户对虚拟世界的感知。

CSDN在今年秋季的英特尔® 信息技术峰会(IDF)上,英特尔曾表示在今年年底将会有集成实感摄像头的产品上市。请问现在有哪些值得推荐的产品和应用方案?

实感技术支持团队:今年年底,集成有业界第一款且最小的英特尔® 实感™ 摄像头的一体机和超极本将上市。英特尔在推动硬件创新的同时,积极联合ISV与软件开发人员开发相适应的软件应用。

我们在中国区与很多ISV进行紧密合作,如腾讯、百度、虹软等一些大型 ISV,还有像广州同声、乾行讯科、触角、云创新等这样的中小型ISV。产品范围覆盖了游戏、工具、教育等各个方面。这些应用完美配合实感摄像头的功能特性,将带给PC用户更佳的人机交互体验。

我们还组织了2014英特尔® RealSense™ 应用挑战赛,旨在提供一个迸发创意比拼技术的更大舞台,鼓励广大的软件开发人员利用实感摄像头以及SDK的特性,开发出创新的应用。

即将于今年底上市的集成了实感摄像头的一体机、超极本等产品,将预装一部分应用。用户在买到产品的第一时间,可享受到实感技术带来的使用乐趣。

明年英特尔还将发布后置型实感摄像头的产品,以及适用于Windows* 及Android* 操作系统的SDK。届时,英特尔® 实感™ 技术产品线将全面覆盖前置、后置摄像头以及Windows、Android操作系统。

 

CSDN能否介绍一下英特尔® 实感™ 技术在中国的技术支持团队?

实感技术支持团队:英特尔软件与解决方案事业部(SSG)合作伙伴关系部(DRD)在中国区有专门的团队来支持实感技术的应用拓展并培育生态系统。我们有客户经理会和客户探讨实感技术的合作前景,也有专门的技术支持工程师团队培训客户掌握实感技术,帮助客户进行实感技术的评估及项目启动的技术部署,及时解决客户在开发过程中遇到的技术问题。

我们的团队分布在上海、北京、深圳、成都、广州等互联网创业公司云集的前沿阵地,与客户密切合作,帮助客户完成基于实感技术的应用开发,并在市场推广、OEM合作等方面提供鼎力协助。

RealSense上海及北京技术团队

英特尔® 实感™ 技术带来的应用创新不仅仅局限于软件层面,这里我们要介绍一个案例,帮助开发者扩展创新想象力。

广州同声公司(TheBestSync, 简称TBS)与英特尔公司合作,基于实感技术开发出体感控制公仔机“趣抓”。传统上,公仔机使用控制杆操作机械爪,用户不能完全体验到抓公仔的乐趣。使用实感技术的“趣抓”,通过手势控制机械爪的移动和抓取动作,令用户有身临其境的感觉。“趣抓”一经面世便得到业界、媒体及玩家的追捧,而这也是英特尔® 实感™ 技术在用户体验创新领域的成功案例。

CSDN请介绍一下你们从事实感应用开发的团队。

广州同声:TBS成立于2011年,主要从事体感控制、增强现实、虚拟现实等方面的应用开发。我们从2012年底开始接触英特尔® 实感™ 技术。在两年的开发过程中,我们在各个应用领域做了深入的探索,开发出多款基于实感技术的应用,其中包括体感工具PIC、游戏类的Findingbbb与BBBGoal、体感互动视频编辑系统PIVIDEO、娱乐类的JOY、体感控制机器人等等。 我们也是英特尔公司组织的面向全球开发者的感知计算/实感技术大赛的积极参赛者,连续参加了3届,曾获得Grand Prize Winner和Third Prize Winner等奖项。

CSDN在今年英特尔公司举办的深圳IDF上,你们展出了一款整合了实感技术的公仔机。可以分享一些使用实感技术开发的经验么?

广州同声:在深圳IDF上,英特尔公司的CEO科再奇先生演示的体感公仔机叫“趣抓”,是TBS基于实感技术开发并获得专利的一款智能娱乐产品,现已进行第一阶段试产并投放市场。我们的三位同事仅用了3天时间就将一台普通的公仔机改装成了可以实现体感控制的“趣抓”原型机。如此的高效率得益于基于实感SDK开发的体感映射工具PIC。在开发过程中,我们感受到实感技术的识别精确度高,令产品容错性更好,实感SDK灵活稳定,令调试难度大幅降低。在产品开发及测试阶段,英特尔软件合作伙伴关系部给予了大力支持,帮助我们及时解决技术问题并提供许多建设性意见,在产品市场化阶段,也提供了鼎力协助。 此外,“趣抓”更融合了互联网社交流行元素,进一步革新了游戏的玩法。11月1日起“趣抓”在广州启动了市场测试。

诊断信息 15532: 循环无法进行矢量化处理:编译时间不足妨碍了循环进行优化

$
0
0

产品版本: Intel(R) Visual Fortran 编译器 XE 15.0.0.070

原因:

使用 Visual Fortran 编译器的优化选项 ( -O2  -Qopt-report:2 )  时出现矢量化报告,表示编译时间不足妨碍了优化。

示例:

 

下面的示例将在优化报告中生成以下注释:

subroutine foo(a, n)

       implicit none
       integer, intent(in) :: n
       double precision, intent(inout) :: a(n)
       integer :: bar
       integer :: i

       i=0
 100   CONTINUE
       a(i)=0
       i=i+1
       if (i .lt. bar()) goto 100

  end subroutine foo

报告来源: 循环嵌套,矢量和自动并行优化 [循环、矢量、并行]

  循环开始  
      注释编号15532: 循环无法进行矢量化处理:编译时间限制阻拦循环进行优化 考虑使用 -O3。
 
  循环结束

解决方法:

使用 -O3 优化选项并参阅诊断信息 15523: 

GOTO 语句阻拦矢量化处理,因为无法计算循环迭代次数。

另请参阅:

矢量化循环要求

矢量化要点

矢量化和优化报告

返回英特尔 Fortran 的矢量化诊断列表

 

英特尔® System Studio 2015 支持矩阵

$
0
0

如果您希望对英特尔® System Studio 2015 组件有更多了解,请向 intelsystemstudio@intel.com 发送电子邮件。

以下是英特尔系统 Studio 2014 支持矩阵的链接。


英特尔® C++ 编译器

主机操作系统:
Linux*

目标操作系统
Yocto Project* 1.4 至 1.6
Tizen* IVI 2.x 至 3.x
WindRiver Linux* 4.0 至 6.0
WindRiver Linux* 4.0 和 5.0 Native
CE Linux* PR35
Android* 4.1.x 至 4.4.x (Android* NDK R9a、R9b、R9c、R9d、R10)

目标平台:
采用 Yocto Project* 1.6 或 WindRiver Linux* 6.0 的英特尔® Quark SoC
采用 Yocto Project* 1.6 的英特尔® Edison 模块

采用 Yocto Project* 或 WindRiver Linux* 的英特尔® 凌动™ 处理器 Z5xx、Z6xx、E6xx、Z3xxx、C2xxx、N2xxx、E38xx、
Intel® E38xx with Tizen*
英特尔® 凌动™ 处理器 CE4100、CE4200、CE5200,采用 CE Linux* PR35 的英特尔® Puma6 媒体网关
英特尔® 酷睿™ 处理器(除面向 CE Linux* PR35 系统的型号)
英特尔® 至强™ 处理器(除面向 CE Linux* PR35 系统的型号)
采用 Android* 的英特尔® 凌动™ 处理器 Z2xxx 和 Z38xx
 

Eclipse* 集成: 支持 Linux*、Android* 访问相关特定信息文档


英特尔® C++ 编译器

主机操作系统:
Windows*

目标操作系统
Windows* 7、8、8.1(注释:对于 Windows 目标构建,主机和目标相同)

Tizen* IVI 2.x 至 3.x
WindRiver Linux* 4.0 至 6.0
Android* 4.1 至 4.4.x(Android* NDK R9a、R9b、R9c、R9d、R10)

目标平台:
采用 Yocto Project* 1.5 或 WindRiver Linux* 6.0 的英特尔® Quark SoC
采用 Yocto Project* 1.6 的英特尔® Edison 模块

采用 Yocto Project* 或 WindRiver Linux* 的英特尔® 凌动™ 处理器 Z5xx、Z6xx、E6xx、Z3xxx、C2xxx、N2xxx、E38xx
英特尔® 酷睿™ 处理器
英特尔® 至强™ 处理器
采用 Android* 的英特尔® 凌动™ 处理器 Z2xxx 和 Z38xx

Eclipse* 集成:  支持;访问针对 Android* 的文档


英特尔® 系统调试器

主机操作系统:
Linux* 和 Windows*
(Linux* 主机上没有 UEFI 和 EDK2 调试)

目标操作系统
Yocto Project* 1.4 至 1.6
Tizen* IVI 2.x 至 3.x
WindRiver Linux* 4.0 至 6.0
WindRiver Linux* 4.0 和 5.0 Native
CE Linux* PR35
Android* 4.1 至 4.4.x

目标平台:
关于闪存编程信息,请向 intelsystemstudio@intel.com 发送电子邮件

采用 Yocto Project* 1.6 或 WindRiver Linux* 5.0 的英特尔® Quark SoC — 与 Olimex* ARM-USB-OCD-H、TinCanTools* FLYSWATTER2 (OpenOCD*) 或 ITP-XDP 3BR (采用 XDP 至 10Pin JTAG 适配器)兼容
英特尔® 凌动™ 处理器 Z5xx、Z6xx、E6xx、Z3xxx、C2xxx、N2xxx、Z2xxx、E38xx
英特尔® 凌动™ 处理器 CE4100、CE4200、CE5200、英特尔® Puma6™ 媒体网关
英特尔®第三代酷睿™ 处理器
英特尔® 第四代酷睿™ 处理器
英特尔® 第五代 酷睿™ M 处理器

英特尔® 第四代至强™ 处理器

Eclipse* 集成: 面向 Eclipse* 3.8 至 4.4 轻度集成


Software Visible Event Nexus 技术 (SVEN)

主机操作系统:
Linux* 和 Windows*

目标操作系统
Yocto Project* 1.4 至 1.6
Tizen* IVI 2.x 至 3.x
WindRiver Linux* 4.0 至 6.0
WindRiver Linux* 4.0 和 5.0 Native
CE Linux* PR35
Android* 4.1 至 4.4.x

目标平台:
采用 Yocto Project* 1.6 或 WindRiver Linux* 5.0 的英特尔® Quark SoC
英特尔® 凌动™ 处理器 Z5xx、Z6xx、E6xx、Z3xxx、C2xxx、N2xxx、Z2xxx、E38xx
英特尔® 凌动™ 处理器 CE4100、CE4200、CE5200、英特尔® Puma6 媒体网关
英特尔® 酷睿™ 处理器
英特尔® 至强™ 处理器

Eclipse* 集成:  支持;用于跟踪查看器


GNU GDB* 调试器

针对以下系统的与构建 GDB 服务器: 面向 IA32 的 Android 4.4、CE Linux PR35、Tizen IVI、WindRiver Linux 4 至 7、 Yocto 1.4 至 1.7。 对于 Intel64 系统,WindRiver Linux 5 上能够使用预构建 GDB 服务器。

主机操作系统:
Linux*、Windows*

目标操作系统
Yocto Project* 1.4 至 1.7
Tizen* IVI 2.x 至 3.x
WindRiver Linux* 4.0 至 6.0
WindRiver Linux* 4.0 和 5.0 Native
CE Linux* PR35
Android* 4.0.x 至 4.4.x

目标平台:
采用 Yocto Project* 1.5 或 WindRiver Linux* 5.0 的英特尔® Quark SoC
采用 Yocto Project* 1.6 的英特尔® Edison 模块

英特尔® 凌动™ 处理器 Z5xx、Z6xx、E6xx、Z3xxx、C2xxx、N2xxx、Z2xxx、E38xx
英特尔® 凌动™ 处理器 CE4100、CE4200、CE5200
英特尔® Puma6 媒体网关
英特尔® 酷睿™ 处理器
英特尔® 至强™ 处理器

Eclipse* 集成:  支持


适用于系统的英特尔® VTune™ Amplifier

主机操作系统:
Linux*

目标操作系统
Yocto Project* 1.4 至 1.6
Tizen* IVI 2.x 至 3.x
WindRiver Linux* 4.0 至 6.0
WindRiver Linux* 4.0 和 5.0 Native
CE Linux* PR35

目标平台:
英特尔® 凌动™ 处理器 Z5xx、Z6xx、E6xx、Z3xxx、C2xxx、N2xxx、Z2xxx、E38xx
英特尔® 凌动™ 处理器 CE4100、CE4200、CE5200、英特尔® Puma6 媒体网关
英特尔® 酷睿™ 处理器
英特尔® 至强™ 处理器

Eclipse* 集成:  不支持


英特尔® Energy Profiler

主机操作系统:
Linux*、Windows*

目标操作系统
Windows* 7、8、8.1

Android* 4.1.x 至 4.4.x

目标平台:
对于 Android - 英特尔® 凌动™ 处理器 Z34XX、Z36XX、Z37XX

对于 Windows* - 英特尔® 凌动™ 处理器 Z34XX、Z36XX、Z37XX、 英特尔® 第四代酷睿™ 处理器

Eclipse* 集成:  不支持


英特尔® Energy Profiler

主机操作系统:
Linux* 和 Windows*

目标操作系统
Yocto Project* 1.2 至 1.5
Tizen* IVI 2.x 至 3.x
WindRiver Linux* 4.0 至 6.0
WindRiver Linux* 4.0 和 5.0 Native
CE Linux* PR35

 

目标平台:
英特尔® 凌动™ 处理器 Z5xx、Z6xx、E6xx、Z3xxx、C2xxx、N2xxx、Z2xxx、E3xxx
英特尔® 凌动™ 处理器 CE4100、CE4200、CE5200、英特尔® Puma6 媒体网关
英特尔® 酷睿™ 处理器
英特尔® 至强™ 处理器

 

Eclipse* 集成:  不支持


英特尔® 数学核心函数库

主机操作系统:
Linux* 和 Windows*

目标操作系统
Yocto Project* 1.2 至 1.5
Tizen* IVI 2.x 至 3.x
WindRiver Linux* 4.0 至 6.0
WindRiver Linux* 4.0 和 5.0 Native
CE Linux* PR35

目标平台:
英特尔® 凌动™ 处理器 Z5xx、Z6xx、E6xx、Z3xxx、C2xxx、N2xxx、Z2xxx、E3xxx
英特尔® 凌动™ 处理器 CE4100、CE4200、CE5200、英特尔® Puma6 媒体网关
英特尔® 酷睿™ 处理器
英特尔® 至强™ 处理器

Eclipse* 集成:支持


英特尔® 集成性能基元

主机操作系统:
Linux* 和 Windows*

目标操作系统
Yocto Project* 1.2 至 1.5
Tizen* IVI 2.x 至 3.x
WindRiver Linux* 4.0 至 6.0
WindRiver Linux* 4.0 和 5.0 Native
CE Linux* PR35
Android* 4.3 至 4.4.x

目标平台:
英特尔® 凌动™ 处理器 Z5xx、Z6xx、E6xx、Z3xxx、C2xxx、N2xxx、Z2xxx、E3xxx
英特尔® 凌动™ 处理器 CE4100、CE4200、CE5200、英特尔® Puma6 媒体网关
英特尔® 酷睿™ 处理器
英特尔® 至强™ 处理器

Eclipse* 集成:支持


英特尔® 系统分析器、帧分析器和平台分析器

主机操作系统:
Linux* 和 Windows*

目标操作系统:
Android* 4.3 至 4.4.x

目标平台:
英特尔® 酷睿™ 处理器
英特尔® 凌动™ 处理器 Z2xxx、Z3xxx

Eclipse* 集成:不支持

 

在 Windows* 主机上调试英特尔® 至强融核™ 应用

$
0
0

目录

简介

英特尔® 至强融核™ 协处理器是一款基于英特尔® 众核架构(英特尔® MIC)的产品。 英特尔® 为该架构提供了调试解决方案,其可调试英特尔® 至强融核™ 协处理器上运行的应用。

英特尔 ® MIC 需要一款调试解决方案出于多种原因。 以下介绍了其中一些主要原因:

  • 开发本地英特尔® MIC 应用与在 IA-32 或英特尔® 64 主机上开发应用一样简单。 在大部分情况下,仅需对其进行交叉编译(/Qmic)。
    但是,英特尔® MIC 架构不同于主机架构。 这些区别可以揭示目前的区别。 此外,对英特尔® MIC 调试不当可能会带来新的问题(如数据对齐,一款应用能否处理数百个以上线程?有效的内存消耗?等。)
  • 开发支持卸载的应用将会带来更多复杂性,因为主机和协处理器在共享工作负载。
  • 一般的低级别分析,追踪执行路径,了解英特尔® MIC 架构的指令集...

面向英特尔® MIC 的调试解决方案

对于 Windows* 主机,英特尔可提供一款调试解决方案 — 面向英特尔® MIC 架构应用的英特尔® 调试器扩展。 它支持能够使用卸载调试功能的应用,并支持原生英特尔® MIC 应用在英特尔® 至强融核™ 协处理器上运行。

如何获得?

如要获取面向基于 Windows* 主机的英特尔® MIC 架构的调试解决方案,您需要以下组件:

集成调试解决方案

来自基于英特尔® 的 GNU* GDB 的调试解决方案:

  • 与 Microsoft Visual Studio* 全面集成,无需命令行版本
  • 支持英特尔® Composer XE 2013 SP1 及更高版本

注:
也可通过在协处理器上使用英特尔版本的 GNU* GDB 以在协处理器上执行纯原生调试。 这在面向 Linux* 主机的文章中进行了介绍:
http://software.intel.com/en-us/articles/debugging-intel-xeon-phi-applications-on-linux-host

为何与 Microsoft Visual Studio* 集成?

  • Microsoft Visual Studio* 是 Windows* 主机上的已有 IDE
  • 集成可以再次使用现有的可用性和特性
  • Fortran 支持与英特尔® Fortran Composer XE

所需的组件

针对英特尔® MIC 架构进行开发和调试将需要以下组件:

  • 英特尔® 至强融核™ 协处理器
  • Windows* Server 2008 RC2、Windows* 7 或更高版本
  • Microsoft Visual Studio* 2012 或更高版本
    在英特尔® Composer XE 2013 SP1 更新 1 中添加了对 Microsoft Visual Studio* 2013 的支持。
  • 英特尔® MPSS 3.1 或更高版本
  • C/C++ 开发:
    面向 Windows* 或更高版本的英特尔® C++ Composer XE 2013 SP1
  • Fortran 开发:
    面向 Windows* 或更高版本的英特尔® Fortran Composer XE 2013 SP1

配置与测试

关键是确保协处理器设置能够正常使用。 否则调试程式可能无法全面运行。

设置英特尔® MPSS:

  • 按照英特尔® MPSS readme-windows.pdf进行设置
  • 确认英特尔®至强融核™ 协处理器是否能够运行

在使用卸载扩展调试应用之前:

  • 参照官方示例:
    C:\Program Files (x86)\Intel\Composer XE 2013 SP1\Samples\en_US
  • 确认卸载代码是否能够正常使用

关键是确保协处理器设置能够正常使用。 否则调试程式可能无法全面运行。

调试前提条件

面向英特尔® MIC 架构的调试程序集成仅在调试信息可能时才可使用:

  • 在调试模式下至少使用以下选项集进行编译:
    /Zi(编译器)和 /DEBUG(链接器)
  • 可选: 未经优化的代码 (/Od) 更易于理解
    ,因为一些临时变量等被删除/或优化掉。
    Visual Studio* Project Properties (Debug Information &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; Optimization)

应用仅可在 64 位中进行调试

  • 将平台设置为 x64
  • 确认 /MACHINE:x64(链接器)是否设置!
    Visual Studio* Project Properties (Machine)

使用卸载扩展调试应用

启动 Microsoft Visual Studio* IDE,使用卸载扩展打开或创建英特尔®至强融核™ 项目。 您可以在英特尔® Composer XE 的示例目录中找到示例,即:

C:\Program Files (x86)\Intel\Composer XE 2013 SP1\Samples\en_US

  • C++\mic_samples.zip    或
  • Fortran\mic_samples.zip

我们将在以下内容中使用官方 C++ 示例中的 intro_SampleC

使用英特尔® C++/Fortran 编译器编译项目。

调试特点

  • 在代码中设置断点(在调试会话期间或之前):
    • 在针对主机和协处理器混合的代码中
    • 调试程序集成自动在主机/协处理器之间分配
  • 运行控制对于原生应用而言相同:
    • 运行/继续
    • 停止/中断
  • 卸载代码在主机上停止运行(卸载线程)
  • 卸载代码在另一条线程的协处理器上运行
  • IDE 同时显示主机/协处理器的信息:
    • 端点
    • 断点
    • 进程/模块
  • 支持多个协处理器:
    • 所显示的数据为混合状态:
      请记住不同的进程和地址空间
    • 无需进一步配置:
      随意调试!

设置断点

Debugging Applications with Offload Extension - Setting Breakpoints

请注意此处的混合断点:
在正常代码中设置的断点(未卸载的)适用于主机。 卸载代码上的断点仅适用于各自的协处理器。
断点窗口显示所有断点(主机和协处理器)。

启动调试

通过菜单(所显示)或 <F5>键正常启动调试:
Debugging Applications with Offload Extension - Start Debugging

继续执行调试,直至遇到卸载代码中设置的断点,该断点能够对协处理器代码进行调试。

线程信息

Debugging Applications with Offload Extension - Thread Information

主机和协处理器的信息处于混合状态。 在上述示例中,线程窗口将显示两个使用其线程进行处理的进程。 一个进程来自主机,负责卸载。 另一个是托管和执行卸载代码的进程,每个协处理器有一个。

其它要求

对于支持卸载调试的应用,还需设置其他环境变量:

  • 英特尔® MPSS 2.1:
    COI_SEP_DISABLE=FALSE
    MYO_WATCHDOG_MONITOR=-1
     
  • 英特尔® MPSS 3.*:
    AMPLXE_COI_DEBUG_SUPPORT=TRUE
    MYO_WATCHDOG_MONITOR=-1

请在启动 Visual Studio* IDE 前设置这些变量!

目前需要它们,但是未来可能会将其淘汰。 请注意,调试程序不能且不应与英特尔® VTune™ Amplifier XE 一起使用。 因此,应禁用 SEP(英特尔® VTune™ Amplifier XE 的组件)。 必须禁用看门狗监控器,因为调试器可能在一段不确定的时间内阻止系统执行。 因此,系统看门狗可能认为被调试的应用(如果不再有反应)死机并将终止它。 对于调试而言,我们不希望看到这种情况。

注:
请勿为产品系统设置这些变量!

调试本机协处理器应用

先决条件

创建本机英特尔®至强融核™ 协处理器应用,将应用转换至协处理器目标并执行:

  • 使用 micnativeloadex.exe(英特尔® MPSS 针对应用提供)C:\Temp\mic-examples\bin\myApp, e.g.:

    > "C:\Program Files\Intel\MPSS\bin\micnativeloadex.exe""C:\Temp\mic-examples\bin\myApp" -d 0
  • 选项 –d 0用于指定第一台设备(基于 0),以防每台设备上有多台协处理器
  • 传输后应用直接执行

micnativeloadex.exe可将特定应用传输至特定协处理器,并直接执行它。 命令本身将锁定,直至传输的应用结束。
使用 micnativeloadex.exe还可照顾到相关性(如库),并对其也进行传输。

此外,也可以使用其他方式来传输和执行本机应用(但是更复杂):

  • SSH/SCP
  • NFS
  • FTP

仅可通过 “Attach to Process…”使用 Start Visual Studio* IDE 来调试本地应用:

  • 使用了 micnativeloadex.exe来传输和执行本机应用
  • 确保应用在连接上之前不执行任何操作,如通过:
static int lockit = 1; while(lockit) { sleep(1); }
  • 连接上之后,将 lockit设置为 0并继续操作。
  • 无需 Visual Studio* 解决方案/计划。

以这种方式每次只能调试一个协处理器。

配置

通过“TOOLS/Options…”菜单打开选项:

Debugging Native Coprocessor Applications - Configuration

它可以告诉调试程序扩展在什么位置查找二进制和源。 它在每次调试新的协处理器本机应用时都需要进行变化。

条目 solib-search-path 目录同样适用于类似的 GNU* GDB 命令。 它支持从构建系统上将路径映射到运行调试程序的主机系统上。

条目 Host Cache Directory用于缓存符号文件。 它可以加速查找大尺寸应用。

附加销售

通过 TOOLS/Attach to Process…菜单打开选项:

Debugging Native Coprocessor Applications - Attach to Process...

指定面向英特尔(R) 架构的英特尔(R) 调试器扩展。 设置 GDBServer 用以执行的 IP 和端口。 GDBServer 的常见端口是 2000,但是我们建议使用非特权式端口 (如 16000)。
短暂延迟后,将列出协处理器卡的进程。 选择一个进行连接。

注:
显示所有用户进程的复选框中不包含针对协处理器的函数,因为用户账户无法从主机映射到目标,反之亦然(Linux* 和 Windows*)。

Intel® Stereo 3D SDK

$
0
0

<?xml:namespace prefix = css3vml />Download Intel® Stereo 3D SDK Alpha

Download Developer’s Guide PDF

简介

立体3D技术主要指通过给观察者两眼分别提供有视差的两张不同图片,让观察者通过大脑对图片信息进行合成从而产生深度感。而通过立体技术制作的立体3D游戏能够让玩家有身临其境的感觉,从而能够创建一个更加真实的沉浸式体验。然而,现在大多数游戏开发者并不具备专业的立体3D知识,很难通过手动设置3D相机参数来得到一个好的立体图像。同时,如果3D相机参数设置不恰当很容易导致眼晕眼胀或者让观察者感觉不到明显的立体效果。不仅如此,由于开发者缺少专业的立体技术知识,往往很难理解游戏坐标空间和真实观察者坐标空间的关系,从而很难对图像的立体效果进行调试。

产品概述

为了解决上述问题,英特尔推出了一款新的软件开发套件Intel® Stereo 3D SDK。这是一个专门为立体3D游戏而设计的开发套件。Intel Stereo 3D SDK 主要面向Windows* 立体3D应用程序开发。它对游戏开发者开放API函数。SDK能够允许开发者简单的使用原来的相机参数作为API函数的输入参数,从而返回合适的立体相机参数,而不需要开发者额外提供其他的输入。SDK的这些便利使得开发者并不需要特别的立体3D知识就能开发出好的立体3D效果,从而可以专注于游戏本身的开发设计上。

SDK 当前支持左右3D格式和上下3D格式. 它具有以下4个主要的功能,如图1所示:

main features
图1. Intel® Stereo 3D SDK 的主要功能

立体相机生成:开发者只需简单输入游戏原有相机参数如:视图矩阵和投影矩阵。SDK会自动生成对应立体场景所需的立体相机矩阵并返回给开发者。


根据场景调整:就像一个优秀的3D摄像师会根据不同场景风格调整立体相机参数一样,SDK也会根据场景的风格动态计算3D相机参数和屏幕视差来达到一个最好的3D体验。


识别虚拟场景ZDP(零视差面):观察者总是为出色的出屏效果而兴奋。SDK能够帮助开发者识别零视差面即显示器平面在虚拟场景的深度,从而帮助开发者方便的创建和调试出屏效果。 .


不同屏幕一致3D体验:当在不同大小屏幕观看相同的3D视频时,观察者通常感知的景深区别会非常大。这是由于景深的变化和屏幕尺寸的变化并不成比例,导致观察者体验区别非常大。而SDK会以屏幕参数作为输入来计算立体相机参数,能够保证景深变化和屏幕尺寸始终有一个正比关系,从而保证观察者对立体内容的一致良好体验。

Intel® Stereo 3D SDK 如何工作

以下3个图很好的表现了SDK的作用. 图2为最佳立体3D体验同时保证了一个良好的感知深度,这也是本SDK所保证的效果,本SDK将避免图3和图4出现的问题。

suitable generated scenes
图2.舒适的感知场景

too much compression
图3.感知深度被过度压缩

out of comfortable area
图4.感知的虚拟场景超过屏幕舒适度范围

技术要求

正常使用SDK,开发者需要英特尔®第二代酷睿处理器或更高端处理器。
 

本SDK支持Microsoft Windows* 8 和 Windows* 7 操作系统。同时开发者还需要安装DirectX* SDK,才能正常使用本SDK。

Support & Feedback

关于本SDK的支持,主要渠道为产品支持论坛。通过支持论坛,你可以问产品相关问题,共享你的开发经验给其他开发者,或者在支持论坛寻求帮助,解决你使用本SDK时遇到的问题。


同时欢迎大家使用支持论坛提交你希望SDK后续能支持的新功能或是对SDK当前功能的评价。你的反馈对英特尔很重要。


此次alpha版本并不保证性能和兼容性。

常见问答

  • 我如何开始?
  • 有什么方法能快速把一个3D 游戏改成一个立体3D 游戏吗?
    • 你只需要在程序中调用enableS3D 函数,把参数设置为true, 同时使用renderS3D调用游戏本身的Render函数。在Render函数里,把相机参数通过调用SDK换成立体相机参数就可以了。
  • 我如何才能自动生成所需的立体相机?
    • 你只须参照开发者指南把你的相机参数输入给SDK,SDK 就会帮你计算并返回合适的立体相机参数。

引用

使用SIMD提升JavaScript应用性能

$
0
0

使用SIMD提升JavaScript应用性能

-胡宁馨,韩盼

1. 背景介绍
      
       现代微处理器利用并行运算在有限的计算资源下提供高性能的处理能力。在一个应用程序中通过单指令多数据( SIMD)指令,处理器细粒度并行处理多个数据项,给应用程序带来了重大的性能改进。 SIMD指令特别适用于图像/音频/视频的处理计算,例如计算机视觉和感知计算。由于其卓越的能效和出色的性能提升, SIMD在现代系统中的作用越来越大。然而到现在为止,JavaScript缺少对SIMD的支持,这样广大的web应用开发者无法在自己的应用中利用SIMD来提升自己应用的性能。随着HTML5的标准化,相信有越来越多的复杂的web应用会随之诞生,同时对性能的需求也会越来越高。SIMD.js是对原有JavaScript的一个扩展使其支持SIMD编程。本文就意在介绍在现有的JavaScript引擎上如何使用SIMD.js编程,并且会利用一些具体的例子来体现性能的提升。
       通过与Mozilla和Google的合作,Intel将SIMD.js语法规范化。通过使用我们建议的SIMD数字类型,现在可以利用纯的JavaScript代码开发出全新类别的计算密集型应用,例如游戏,图像/视频处理软件,而不需要额外的插件或不可移植的原生代码。

2. SIMD

* 什么是SIMD
正如上面提到, SIMD代表的是单指令,多数据。 SIMD利用数据的并行性同时对多个数据进行相同的操作。今天,大量的处理器具有SIMD操作指令。 SIMD运算可以大大受益于如3D图形和音频/视频处理中的多媒体应用领域的应用。
* SIMD编程
一个SIMD值有多个分量。在下面这个例子中,我们使用的是两个长度为4的SIMD向量,每个分量被命名的x,y ,z和w。下图显示了一个SIMD加法运算。不需要对4个独立的分量执行4次加法运算, SIMD允许同时对四个分量一齐进行加操作。因为采用较少的操作次数,所以大大提高了新能并且节省了电能。

 

3. SIMD在JavaScript中的使用
* 数据类型
SIMD.js在现有的JavaScript中增加了新的数据类型,如下表:

float32x4

4 IEEE-754 32-bit Floating Point Numbers

int32x4

4 32-bit Signed Integers

float64x2

2 IEEE-754 64-bit Floating Point Numbers

Float32x4Array

Typed Array of float32x4

Int32x4Array

Typed Array of int32x4

Float64x2Array

Typed Array of float64x2

这些数据类型在使用的过程中有一些要注意的地方。在JavaScript中SIMD的数据类型是不可变的,这意味着不能直接改变一个SIMD的实例。尽管一个SIMD实例中有4个不同值的分量,但是却不能把它当做一个链表来使用。正确的做法应当是在不同的SIMD数据之间进行操作进而产生新的SIMD数据。下文就介绍一些常用的SIMD操作。

  • 操作

Constructor

var a = SIMD.float32x4(1.0, 2.0, 3.0, 4.0);

1.0

2.0

3.0

4.0

var b = SIMD.float32x4.zero();

0.0

0.0

0.0

0.0

 var c = SIMD.float32x4.splat(1.0);

1.0

1.0

1.0

1.0

 Access and Modify

var a = SIMD.float32x4(1.0, 2.0, 3.0, 4.0);

1.0

2.0

3.0

4.0

var b = a.x; // 取得a中第一个分量的值,其他依次为y,z,w.

var c = a.withX(5.0); //改变第一个分量的值,形成一个新的SIMD数据

5.0

2.0

3.0

4.0

Arithmetic

var a = SIMD.float32x4(1.0, 2.0, 3.0, 4.0);

var b = SIMD.float32x4(5.0, 10.0, 15.0, 20.0);

var c = SIMD.float32x4.add(a,b);

1.0

2.0

3.0

4.0

                  +             

5.0

10.0

15.0

20.0

              =

6.0

12.0

18.0

24.0

 Shuffle

var a = SIMD.float32x4(1.0, 2.0, 3.0, 4.0);

1.0

2.0

3.0

4.0

var b = SIMD.float32x4.shuffle(a, SIMD.float32x4.XXYY);

1.0

1.0

2.0

2.0

var c = SIMD.float32x4.shuffle(a, SIMD.float32x4.WWWW);

4.0

4.0

4.0

4.0

var d = SIMD.float32x4.shuffle(a, SIMD.float32x4.WZYX);

4.0

3.0

2.0

1.0

 

Compare

var a = SIMD.float32x4(1.0, 2.0, 3.0, 4.0);

1.0

2.0

3.0

4.0

var b = SIMD.float32x4(0.0, 3.0, 5.0, 2.0);

0.0

3.0

5.0

2.0

vargreaterThan = SIMD.float32x4.greaterThan(a, b);

0xF

0x0

0x0

0xF

 

Example

求平均数:

function average(list) {

        var n = list.length;

        var sum = 0.0;

for (inti = 0; i< n; i++) {

                        sum += list[i];

 }

 return sum / n;

}

SIMD写法:

function average(f32x4list) {

        var n = f32x4list.length;

        var sum = SIMD.float32x4.zero();

        for (inti = 0; i< n; i++) {

                        sum = SIMD.float32x4.add(sum, f32x4list.getAt(i));

 }

        var total = sum.x + sum.y + sum.z + sum.w;

return total / (n * 4);

}

总的来说,SIMD.js中的数据类型和操作可以概括为下图:

完整的API可以参考Johnpolyfill实现:https://github.com/johnmccutchan/ecmascript_simd/blob/master/src/ecmascript_simd.js

 {C}{C}{C}{C}{C}{C}{C}{C}·         性能分析

下图展示了在一些基本JavaScript运算benchmark上的性能提升,红线代表的是4倍性能提升,4倍是理论上的使用向量宽度为4SIMD数据类型的加速比。

 以下两张图展示一个简单的小鸟图形示例,分别在开启SIMD和关闭SIMD的情况下小鸟的个数有明显的不同。

 

  SIMD.js可以和WebWorker整合使用会得到更好的性能提升。以下四张图分别展示了在没有开启SIMD,开启SIMD,开启SIMD并且两个WebWorker同时渲染,开启SIMD并且三个WebWorker同时渲染的效果图。

 

   4.       SIMD.js JavaScript引擎中的实现

20148月, JavaScript标准化组织TC39已经批准了SIMD.js成为第一阶段的标准提案。与此同时,SIMD.js已经实现在MozillaFirefox Nightly浏览器和基于Chromium浏览器的原型中,微软的Internet Explorer浏览器也正在考虑实现SIMD.js

SIMD.js API的设计考虑了JavaScript引擎实现的效率。优化过的JavaScript引擎可以将SIMD.js API的调用最终编译为底层硬件的支持的SIMD指令。比如,基于Intel的平台,JavaScript引擎会将SIMD.float32x4.add编译为addps指令,将SIMD.float32x4.mul编译为mulps指令。相应的,针对其他硬件平台,JavaScript也可以生成对应的指令。这些指令可以同时对四个浮点数进行加法或则乘法操作,从而达到提升性能和节省电能的效果。

5.           SIMD.js 重要性

随着HTML5应用的普及,越来越多的web开发者会利用新的技术开发越来越复杂的web应用,而SIMD技术的应用会使这些web应用的性能大大提高。例如一些 WebGLCanvasGamesPhysicsCrypto等都是典型的可以利用SIMD加速的应用。

另外SIMD代码的执行只需要相对少数的指令,相对少数的指令意味对电能也是一种节省。

 6.      References

 

Direct3D* 12 — 提高 PC 上的控制台 API 效率和性能

$
0
0

Direct3D* 12 概述
作者: Michael Coppock

下载 PDF

摘要
Microsoft Direct3D* 12 是 PC 游戏技术令人兴奋的跨越式发展,可帮助开发人员更好地控制游戏,提高 CPU 的效率和可扩展性。


 

目录

简介

    1.0 – 突破过去
    1.1 – 接近完美

2.0 – 管线状态对象

3.0 – 资源绑定

    3.1 – 资源 Hazards
    3.2 – 资源存放管理
    3.3 – 状态镜像

4.0 – 堆和表

    4.1 – 冗余资源绑定
    4.2 – 描述符
    4.3 –
    4.4 –
    4.5 – 无绑定和高效性
    4.6 – 渲染环境概述

5.0 – 捆绑包

    5.1 – 冗余渲染指令
    5.2 – 什么是捆绑包?
    5.3 – 代码效率

6.0 – 命令列表

    6.1 – 命令创建并行性
    6.2 – 列表和队列
    6.3 – 命令队列流

7.0 – 动态堆

8.0 – CPU 并行性

9.0 – 总结

参考资料和相关链接

声明和免责条款

简介

在 GDC 2014 上,Microsoft 发布了一条震惊整个 PC 游戏界的消息 — 2015 年将推出下一代 Direct3D,即 Direct3D 第12 版。 D3D 12 回归低级别编程,可支持游戏人员更好地进行控制,并推出许多令人兴奋的新特性。 D3D 12 开发团队主要着力于降低 CPU 开销,提高各 CPU 内核间的可扩展性。 其目标是提高控制台 API 效率和性能,以便控制台游戏能够更高效地使用 CPU/GPU 并获得更出色的结果。 在 PC 游戏领域,线程 0 通常执行大部分,甚至全部的任务。 其他的线程仅处理操作系统或其他系统任务。 真正的多线程 PC 游戏很少。 Microsoft 希望通过 D3D 12 改变这一现状。D3D 12 是 D3D 11 渲染功能的超集, 这表示现代 GPU 能够运行 D3D 12,因为它能够更高效地利用当下的多核 CPU 和 GPU。 用户无需额外花钱购买新的 GPU 即可采用 D3D 12。 基于英特尔® 处理器系统的 PC 游戏拥有光明的未来!

1.0 突破过去

低级别编程在控制台行业非常常见,因为每个控制台的规格是固定的。 游戏开发人员将有时间对游戏进行调整,并尽可能地利用 Xbox One* 或 PlayStation* 4 的全部功能和性能。 PC 是一个天生的灵活平台,包含无数个选件。 在开发新的 PC 游戏时,可以制定许多种计划。 OpenGL* 和 Direct3D* 等高级别 API 可以帮助简化开发。 它们能够极大地减轻负担,以便开发人员将更多地精力放在开发游戏上。 问题是,API 以及(从更小一点地范围来说)驱动程序已经达到非常复杂的地步,以至于影响了帧的渲染,从而降低了性能。 因此,大家将目光投向低级别编程。

基于 PC 的低级别编程随着 MS-DOS* 时代的结束而淡出,特定厂商 API (如 3DFX* 提供的 3Dglide*)让位于 Direct3D 等 API。 PC 在便捷性和灵活性方面的性能不断落后。 硬件市场日趋复杂,能够提供大量选项。 开发时间增加,因为开发人员希望确保购买他们游戏的玩家都能够很好地玩游戏。 不仅软件端的情况发生了变化,而且 CPU 能效也变得比性能更重要。 相比原始频率,CPU 中的多核和多线程以及现代 GPU 的并行渲染才是影响未来性能的主要方面。 我们需要将 PC 游戏迁移至游戏控制台。 我们需要更好、更有效地利用所有内核和线程。 我们需要将 PC 游戏发展为 21 世纪的现代游戏。

1.1 接近完美

为了使游戏“接近完美”,我们必须降低 API 和驱动程序的尺寸和复杂性。 我们应该减少硬件和游戏本身之间的层。 API 和驱动程序花费了太多时间转换命令和调用。 游戏开发人员将重获部分(甚至大部分)的控制。 D3D 12 降低的开销将可提高性能,游戏和 GPU 硬件之间更少的层意味着提供外观和性能更出色的游戏。 另一方面是,某些开发人员可能不想控制 API 处理的领域,如 GPU 内存管理, 也可能这是游戏引擎开发人员想要进入的领域,只有时间能够告诉我们结果。 鉴于 D3D 12 的发布还需要一段时间,我们还有时间去弄清楚这件事情。 既然可能拥有如此光明的前景,那么如何实现呢? 主要通过四种新特性,管线状态对象 (Pipeline State Object)、命令列表、捆绑包和堆。

2.0 管线状态对象

为了更好地讨论管线状态对象 (PSO),我们先来回顾一下 D3D 11 渲染环境,然后再了解一下 D3D 12 中的变化。 图 1 中包含 D3D 11 渲染环境,该环境是 D3D 开发领袖 Max McMullen 于四月份在 BUILD 2014 上展示的内容。


图 1: D3D 11 渲染环境。 [转载获得 Microsoft 许可。]

大号的粗体箭头表示每条管线的状态。 每个状态可根据游戏的需求进行检索或设置。 底部的其他状态是固定函数状态,如视口或裁剪矩形。 本土中的其他相关特性将在本文的后续章节中进行介绍。 对于 PSO 讨论,我们只需要查看图表的左侧。 D3D 11 的小型状态对象相比 D3D 9 的 CPU 开销更低,但是驱动程序采用这些小型状态对象并在渲染时将其融入 GPU 代码还需要其他的操作。 我们将称其为硬件失配开销。 接下来我们通过图 2 中了解一下 BUILD 2014 的其他图表。


图 2: 采用小型对象的 D3D 11 管线会频繁导致产生硬件失配开销。

左侧展示了 D3D 9 风格的管线,应用使用该管线执行任务。 图 2 右侧的硬件需要进行编程。 状态 1 代表着色器代码。 状态 2 是光栅化单元以及将光栅化单元与着色器链接的控制流的结合。 状态 3 是混合着色器和像素着色器之间的链接。 D3D 顶点着色器会影响硬件状态 1 & 2、光栅化程序状态 2、像素着色器状态 1-3 等。 多数驱动程序不希望与应用同时提交调用。 它们更希望进行记录,直至任务完成,以便了解应用真正想要什么。 这表示,其他 CPU 开销(如旧数据和过期数据)将标记为“脏数据”。 驱动程序的控制流将在绘制时检查每个对象的状态,并编写硬件以匹配游戏设置的状态。 另外执行这些任务后,资源将会耗尽并可能会出现问题。 理想状态下,游戏设置管线状态后,驱动程序将会了解游戏的目的并对硬件执行一次编写。 图 3 展示了 D3D 12 管线,该管线在管线状态对象 (PSO) 中执行该操作。


图 3: D3D 12 管线状态优化简化了流程。

图 3 展示了开销降低的简化流程。 包含每个着色器的状态信息的一个 PSO 可以在一个文本中设置所有硬件状态。 请记住,一些状态在 D3D 11 渲染器环境中标记为“其他”。 D3D 12 团队意识到应该减小 PSO 的尺寸,并允许游戏在不影响已编译 PSO 的前提下更改渲染器目标。 视口和裁剪矩形等特性独立出来,与其他的管线在编程上无关联(图 4)。


图 4: 左侧展示了新的 D3D 12 PSO,其包含更大的状态,能够提供更高的效率。

相比以前单独设置和读取每个状态,我们现在采用一个视角,减少或完全消除了硬件失配开销。 应用在需要时设置 PSO,驱动程序采用 API 命令并将其转换为 GPU 代码,同时不增加流控制开销。 这一“接近完美”的方法代表绘制命令将需要更少的周期,从而可提高性能。

3.0 资源绑定

在讨论资源绑定变更之前,我们需要快速回顾 D3D 11 中的资源绑定模型。 图 5 再次展示了渲染环境图形,其中左侧是 D3D 12 PSO,右侧是 D3D 11 资源绑定模型。


图 5: 左侧为 D3D 12 PSO,右侧为 D3D 11 资源绑定模型的渲染器环境。

在图 5 中,Explicit 绑定点位于每个着色器的右侧。 Explicit 模型表示管线中的每个阶段都有其要指称的具体资源。 它们与 GPU 内存中的点参考资源绑定。 这些资源可能是纹理、渲染目标、缓冲、UAV 等。资源绑定很久之前就已经发布,事实上,它在 D3D 发布之前便已发布。 其目标是处理场景是处理场景背后的多种属性,并有效帮助游戏提交渲染命令。 但是,系统需要在三个关键区域运行许多绑定检查。 下一部分将会介绍这些区域,以及 D3D 团队如何针对 D3D 12 对其进行优化。

3.1 资源 Hazard

通常,Hazard 是转移,如从渲染目标迁移至纹理。 游戏可能需要渲染一帧,将其用作场景的环境贴图。 游戏完成环境贴图的渲染,现在想要将其用作纹理。 在这一过程中,运行时和驱动程序将会追踪某一对象何时绑定为渲染目标或纹理。 如果运行时和驱动程序发现有绑定为二者的对象,将会解除绑定以前的设置,并遵循最新的设置。 通过这种方式,游戏能够按照需求进行切换,软件堆栈能够在后台管理切换。 驱动程序也需要刷新 GPU 管线才能够将渲染目标用作纹理。 否则,在 GPU 中被检索到之前,像素便会被读取,您将无法获得一致的状态。 本质上,Hazard 是需要在 GPU 进行额外处理以确保数据一致的对象。

与 D3D 12 中的其他特性和增强一样,解决办法提供更多的游戏控制。 API 和驱动程序为什么要费力追踪一帧中某一点的时间? 从一个资源切换为另一资源大约需 1/60 秒的时间。 通过重新支持游戏进行控制,将降低开销,而且当游戏转换资源时,仅需支付一次成本(图 6)。


D3D12_RESOURCE_BARRIER_DESC Desc;
Desc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
Desc.Transition.pResource   = pRTTexture;
Desc.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
Desc.Transition.StateBefore = D3D12_RESOURCE_USAGE_RENDER_TARGET;
Desc.Transition.StateAfter  = D3D12_RESOURCE_USAGE_PIXEL_SHADER_RESOURCE;
pContext->ResourceBarrier( 1, &Desc );
图 6: D3D 12 中添加的资源屏障 API

图 6 中的资源屏障 API 可声明一个资源及其源和目标用途,然后调用函数以告知运行时和驱动程序该转换。 它成为明确的对象,而非需要使用大量条件逻辑跨帧渲染器进行追踪的对象,从而使其成为每帧的单一时间或游戏需要进行转换的频率。

3.2 资源存放管理

D3D 11(及其更低版本)以调用在排队为前提运行。 游戏相信 API 能够立即执行调用。 然而事实并非如此。 GPU 的命令都无法即时调用和执行。 虽然这能够提高 GPU 和 CPU 之间的并行性和效率,但是需要大量的引用计数和追踪。 这些计数和追踪都需要占用 CPU。

为了修复这一点,我们在游戏中添加了对资源生命周期的显性控制。 D3D 12 不再隐藏 GPU 的排队特性。 游戏中添加了围栏 API,以追踪 GPU 进程。 游戏可以在特定点(每帧一次)进行检查,并确认不再需要哪些资源,然后将其内存释放,以作他用。 将不再需要使用额外逻辑追踪帧渲染器的时长,以释放资源和内存。

3.3 状态镜像

对上述三个区域进行优化后,发现了另一个可能会对效率进行提升的元素(尽管性能的提升较小)。 设置绑定点后,运行时将会追踪该点,以便游戏以后调用 Get 以了解绑定至管线的点。 将绑定点镜像或复制。 游戏中添加了一个特性,旨在帮助中间件更轻松地操作,以便组件化软件发现渲染环境的当前状态。 资源绑定进行优化后,将不再需要镜像状态副本。 除了将流控制从上述三个区域中删除之外,还删除了用于状态镜像的 Gets。

4.0 堆和表

还有一个重要的资源变更需要介绍一下。 第四部分末将会展示整个 D3D 12 渲染环境。 全新 D3D 12 渲染环境是提高 API CPU 效率的第一步。

4.1 冗余资源绑定

对几个游戏进行分析后,D3D 开发团队发现,一般情况下,游戏在不同帧中使用相同的命令序列。 不仅是命令,绑定在不同的帧间也是相同的。 CPU 生成一系列绑定,比如 12 个,在一帧上绘制对象。 通常,CPU 需要为下一帧再次生成这 12 个绑定。 为什么不将这些绑定缓存,并为开发人员提供一个指向缓存的命令,以便再次使用相同的绑定?

第三部分中,我们介绍了队列。 当发起调用时,游戏认为 API 将立即执行调用。 但是事实并非如此。 命令被放入队列,在队列中所有命令都将延迟,并由 GPU 延后执行。 因此,如果您对我们之前说过的 12 个绑定中的一个绑定做出变更,驱动程序将会把 12 个绑定全部复制到新的位置,对副本进行编辑,然后通知 GPU 开始使用复制的绑定。 通常 12 个绑定中多数仅包含静态值,只有少数几个捆绑包含需要更新的动态值。 当游戏想要对这些绑定进行部分变更,它需要复制全部绑定,这样,较小的变更花费了大量的 CPU 成本。

4.2 描述符

什么描述符? 简言之,它是定义资源参数的数据。 本质上,它是 D3D 11 视图对象背后的数据, 没有操作系统生命周期管理。 它只是 GPU 内存中的不透明数据。 它包含类型和格式信息、mip 纹理计数以及一个指向像素数据的指针。 描述符是新资源绑定模型的核心。


图 7: D3D 12 描述符,定义资源参数的小型数据。

4.3 堆

当在 D3D 11 中设置视图时,它将会把描述符复制到 GPU 内存中将读取描述符的位置。 如果您在同一个位置设置新视图,D3D 11 将会把描述符复制到新的内存位置,并告知 GPU 在下一个绘制命令中从新位置读取。 当对描述符执行创建、复制等操作时,D3D 12 将提供对游戏或应用的明确控制。


图 8

堆(图 8)只是大型的描述符阵列。 您可以重新使用以前的绘制或帧中的描述符。 您还可以根据需要传输新的描述符。 布局归游戏所有,因此操作堆无需太多的开销。 堆尺寸取决于 GPU 架构。 较老的低功耗 GPU 的尺寸限制在 65k,而高端 GPU 的尺寸受限于内存。 较低功耗的 GPU 有可能超过堆。 因此,D3D 12 允许使用多个堆,从一个描述符堆切换至下一个。 但是,在某些 GPU 的堆之间切换会导致出现刷新,因此必须谨慎使用该特性。

我们如何将着色器代码与特定描述符或描述符集相关联? 解决方案? 表。

4.4 表

表是堆的起始索引和尺寸。 它们是环境点 (context points),但不是 API 对象。 您可以根据需要在每个着色器阶段部署一个或多个表。 例如,绘制调用的定点着色器可以部署一个表,指向堆中偏移量在 20 至 30 的描述符。 当下一次绘制开始时,偏移量将更改为 32 至 40。


图 9

使用当前硬件,D3D 12 在 PSO 可以在每个着色器阶段处理多个表。 您可以部署一个表,在该表中仅添加在不同调用之间频繁变化的数据;然后再部署一个表,在该表中仅添加在不同调用、帧之间处于静态的数据。 这样做可以避免将所有描述符从一个调用复制到下一个。 但是,较旧的 GPU 仅可在每个着色器阶段部署一个表。 多表仅支持在当前和以后的硬件上使用。

4.5 无绑定和高效性

描述符堆和表是 D3D 团队对无绑定渲染的采用,只是无法在 PC 硬件间扩展。 D3D 12 支持所有系统,从低端的系统芯片到高端的独立显卡。 此统一方式可为游戏开发人员提供许多绑定流可能性。 此外,新模型包括多个频率的更新。 支持包含静态绑定的高速缓存表重新使用,同时支持包含在每次绘制时不断变化的数据的动态表,从而在每次执行新绘制任务时无需复制全部绑定。

4.6 渲染环境概述

图 10 展示了目前讨论的 D3D 12 变化的渲染环境。 它还展示了新 PSO 以及 Gets 的删除,但是仍然包含 D3D 11 显性绑定点。


图 10: 本文中目前介绍的 D3D 12 变化的渲染环境。

接下来,我们将 D3D 11 渲染环境的最后一部分删除,并添加描述符表和堆。 现在,我们在每个着色器阶段部署了一个表或多个表,如像素着色器所示。


图 11: D3D 12 的整个渲染环境。

精细的状态对象消失,取而代之的是管线状态对象。 Hazard 追踪和状态镜像删除。 显性绑定点更换为应用/游戏管理的内存对象。 通过减少开支,删除 API 和驱动程序中的控制流和逻辑,CPU 效率得到提升。

5.0 捆绑包

我们结束在 D3D 12 中添加新的渲染器环境,观察 D3D 12 如何将控制归还游戏,使其“接近完美”。 但是,D3D 12 删除或简化 API churn(混乱)需要执行更多的操作。 API 中仍然有开销降低性能,因此我们需要其他方式充分使用 CPU。 命令序列如何? 重复序列有多少,如何使它们更高效?

5.1 冗余渲染命令

通过逐帧检查渲染命令,Microsoft D3D 团队发现,只有 5-10% 命令序列删除或添加。 其余的命令都是在不同的帧间重复使用。 因此,90-95% 的时间,CPU 都在重复相同的命令序列。

如何使其更高效? D3D 为何目前尚未尝试它? 在 BUILD 2014 上,Max McMullen 表示:“很难构建一种方法,以一致、可靠的方式来记录命令。 在不同驱动程序的不同 GPU 上以相同的方式运行,并保持同步可以确保一致。” 游戏需要所记录的命令序列与单独的命令的运行速度一样快。 什么改变了现状? D3D 改变了现状。 借助全新的 PSO、描述符堆和表,需要记录的状态以及播放命令得到极大简化。

5.2 什么是捆绑包?

捆绑包是一个小型命令列表,它记录了一次,但可在不同的帧和同一帧上重复使用,重复使用没有任何限制。 捆绑包可以在任何线程上创建,并可无数次使用。 捆绑包没有和 PSO 状态绑定,这表示 PSO 可以更新描述符表,然后当捆绑包使用不同的绑定再次运行时,游戏将得到其他的结果。 如同 Excel* 电子数据表中的公式,算法是一样的,只是结果取决于源数据。 我们添加了一些限制,以确保驱动程序能够有效执行捆绑包,其中一个是确保任何命令都无法更改渲染目标。 但是,我们仍然保留了许多能够记录和回放的命令。


图 12: 捆绑包是能够根据需要进行记录和回放的多次重复命令。

图 12 左侧是渲染环境示例,CPU 生成一系列命令,然后传递至 GPU 执行。 右侧是两个捆绑包,其中包含一个记录在不同线程上以便重复使用的命令。 当 GPU 运行命令时,最终会运行一个执行包命令 (execute bundle command)。 然后,它将回放所记录的捆绑包。 完成后,它将返回命令序列,继续查找其他捆绑包执行命令。 然后读取并回放第二个捆绑包,然后再继续。

5.3 代码效率

我们已经介绍了 GPU 中的控制流。 现在我们来看一下捆绑包如何简化代码。

不包含捆绑包的示例代码

我们在下图展示了一个设置管线状态和描述符表的设置阶段。 我们在接下来的图表中展示了两个对象绘制。 它们两个使用了相同的命令序列,只有常量不同。 这是典型的 D3D 11 和更旧的代码。


// Setup
pContext->SetPipelineState(pPSO);
pContext->SetRenderTargetViewTable(0, 1, FALSE, 0);
pContext->SetVertexBufferTable(0, 1);
pContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
图 14: 典型 D3D 11 代码中的设置阶段

 


// Draw 1
pContext->SetConstantBufferViewTable(D3D12_SHADER_STAGE_PIXEL, 0, 1);
pContext->SetShaderResourceViewTable(D3D12_SHADER_STAGE_PIXEL, 0, 1);
pContext->DrawInstanced(6, 1, 0, 0);
pContext->SetShaderResourceViewTable(D3D12_SHADER_STAGE_PIXEL, 1, 1);
pContext->DrawInstanced(6, 1, 6, 0);
图 15: 典型 D3D 11 代码中的绘制

 


// Draw 2
pContext->SetConstantBufferViewTable(D3D12_SHADER_STAGE_PIXEL, 1, 1);
pContext->SetShaderResourceViewTable(D3D12_SHADER_STAGE_PIXEL, 0, 1);
pContext->DrawInstanced(6, 1, 0, 0);
pContext->SetShaderResourceViewTable(D3D12_SHADER_STAGE_PIXEL, 1, 1);
pContext->DrawInstanced(6, 1, 6, 0);
图 16: 典型 D3D 11 代码中的绘制

 

包含捆绑包的示例


// Create bundle
pDevice->CreateCommandList(D3D12_COMMAND_LIST_TYPE_BUNDLE, pBundleAllocator, pPSO, pDescriptorHeap, &pBundle);
图 17: 捆绑包创建代码示例

 


// Record commands
pBundle->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
pBundle->SetShaderResourceViewTable(D3D12_SHADER_STAGE_PIXEL, 0, 1);
pBundle->DrawInstanced(6, 1, 0, 0);
pBundle->SetShaderResourceViewTable(D3D12_SHADER_STAGE_PIXEL, 1, 1);
pBundle->DrawInstanced(6, 1, 6, 0);
pBundle->Close();
图 18: 捆绑包记录代码示例

 

接下来,我们了解一下与 D3D 12 中的捆绑包相同的命令序列。 以下第一个调用可以创建一个捆绑包。 该操作可以发生在任何线程上。 在下一个阶段,将记录命令序列。 这些命令与我们在之前的示例中看到的命令相同。

图 17 和 18 中的代码示例与图 14-16 中的非捆绑包代码执行的任务相同。 它们展示了捆绑包如何减少所需的调用数,执行相同的任务。 GPU 仍然执行相同的命令并得出相同的结果,只是效率更高。

6.0 命令列表

通过捆绑包、PSO、描述符堆和表,您可以了解 D3D 12 如何提高 CPU 效率,并为开发人员提供更多控制。 PSO 和描述符模型支持使用捆绑包,它们依次用于常见命令和重复命令。 这种更简单的“接近完美”的方法降低了开销,并允许更高效地利用 CPU 实现“控制台 API 效率和性能”。 之前我们讨论过,PC 游戏使用线程 0 执行大部分,甚至全部任务,而其他线程处理其他操作系统或系统任务。 充分利用 PC 游戏中的多核或线程非常困难。 实现游戏多线程通常需要大量的人力和资源。 D3D 开发团队希望借助 D3D 12 改变这一点。

6.1 命令创建并行性

本文中已多次提及,延迟执行的命令看似立即执行,实际上却需要排队并延迟执行。 该函数在 D3D 12 中予以保留,但是对游戏透明。 没有立即执行的环境,因为所有数据都需要延迟执行。 线程可以并行生成一个命令,以完成馈送至 API 对象的一列命令(即命令队列)。 GPU 在命令通过命令队列提交之前将不会执行。 队列是命令的排序,命令列表是上述命令的记录。 如何区别命令列表和捆绑包? 命令列表专门进行设计并优化,因此多条线程可以同时生成命令。 命令列表使用一次后将会从内存中删除,然后该位置将会记录一个新的列表。 捆绑包专门针对一帧或多帧中常使用的渲染命令的多次使用而设计。

在 D3D 11 中,该团队尝试了命令并行性,又称延迟环境 (deferred context)。 但是,由于所需的开销,它无法达到 D3D 团队的性能目标。 进一步的分析显示,许多位置需要大量串行开销,这导致不同的 CPU 内核之间的扩展性较差。 借助 CPU 高效性设计(见第 2-5 章),D3D 12 中消除了某些串行开销。

6.2 列表和队列

想象一下,两条线程生成一个渲染命令列表。 一个序列需要在另一个序列之前运行。 如果有 hazard,一条线程可以使用一个资源作为纹理,其他的线程使用同一个资源作为渲染目标。 驱动程序需要了解渲染时的资源利用率,并解决 hazard,确保提供一致的数据。 Hazard 追踪是 D3D 11 中序列化开销之一。 在 D3D 12 中,游戏(而非驱动程序)负责 hazard 追踪。

D3D 11 允许使用多个延迟环境,但是它们需要消耗成本。 驱动程序按资源追踪状态。 因此当您开始为延迟环境记录命令时,驱动程序需要分配内存,追踪所使用的每个资源的状态。 当生成延迟环境时,将会保留该内存。 完成后,驱动程序需要将所有追踪对象从内存中删除。 这将导致不必要的开销。 游戏可以声明 API 级别能够并行生成的最大命令列表数量。 然后,驱动程序将在同一部分内存中提前安排和分配所有追踪对象。

D3D 11 中常使用动态缓冲区(环境、顶点等),但是后台有许多丢弃的内存追踪实例缓冲区。 例如,可能会有两个并行生成的命令列表,且调用了 MapDiscard。 提交列表后,驱动程序必须在第二个命令列表打补丁,以纠正丢弃的缓冲区的信息。 与之前的 hazard 一样,这也需要一些开销。 D3D 12 将重命名控制交给游戏;动态缓冲区消失。 与此同时,游戏获得精细控制。 它可以构建自己的分配程序,并可以根据需要再次划分缓冲区。 然后命令可以指向内存中明确的点。

第 3.1 部分的讨论,在 D3D 11 中,运行时和驱动程序追踪资源生命周期。 这需要大量的资源进行计数和追踪,所有内容必须在提交时解决。 在 D3D 12 中,游戏拥有资源生命周期以及对 hazard 的控制,这消除了串行开销,从而提高了 CPU 的效率。 对这四个区域进行优化后,D3D 12 的并行命令生成更加高效,从而改进了 CPU 的并行性。 另外,D3D 开发团队目标正在构建新的驱动程序模型 WDDM 2.0,计划进一步进行优化,降低名称列表提交成本。

6.3 命令队列流


图 19: 命令队列,其中包含并行生成的两个命令列表以及两个重复使用命令捆绑包。

图 19 展示了 第 5.2 部分的捆绑包图表,但是它为多线程。 左侧的命令队列是提交至 GPU 的活动的序列。 中间是两个命令列表,右侧是场景开始前记录的两个捆绑包。 首先介绍一下命令列表,它们是针对不同部分的场景并行生成,命令列表 1 完成记录,提交至命令队列,然后 GPU 开始运行它。 同时,命令队列控制流开始,命令列表 2 记录在线程 2 上。 当 GPU 运行命令列表 1 时,线程 2 完成命令列表 2 的生成,并将其提交至命令队列。 当命令队列完成命令列表 1 的运行时,将按照顺序迁移至命令列表 2. 命令队列按照 GPU 需要执行命令的顺序排序。 虽然命令列表 2 在 GPU 完成命令列表 1 的运行前生成并提交至命令队列,但是在命令列表 1 的运行完成前不会执行命令列表 2。 D3D 12 支持在整个流程中更高效地并行。

7.0 动态堆

正如之前的讨论,游戏控制资源重命名,以便能够并行生成命令。 此外,D3D 12 中的资源重命名进行了简化。 D3D 11 对缓冲区进行了分类,将其分为顶点、常量和索引缓冲区。 游戏开发人员需要借助该功能按照自己希望的方式使用保留的内存。 D3D 团队遵从了这一需求。 D3D 12 缓冲区不再分类。 缓冲区只是游戏根据需要为帧(或多个帧)分配的必要尺寸的一块内存。 我们甚至可以根据需要使用并再次划分堆分配程序,从而创建了更高效的流程。 D3D 12 还有一个标准基准。 只要游戏使用标准基准,GPU 就能够读取数据。 标准化程度越高,就越容易创建能够在 CPU、GPU 和其他硬件等变量间流畅运行的内容。 此外,内存也是持续映射,这样,CPU 便能够一直知道地址。 它支持更出色的 CPU 并行性,因为您可以部署一个线程,将 CPU 指向该内存,然后让 CPU 决定某一帧需要什么数据。


图 20: 缓冲区分配与再次分配

图 20 顶部是包含分类缓冲区的 D3D 11 风格。 其下方是由游戏控制堆的全新 D3D 12 模型。 呈现出来的是一块连续的内存,而非位于其他内存位置的不同类型的缓冲区。 此外,游戏还将根据当前或未来数帧的渲染需求来调整缓冲区的尺寸。

8.0 CPU 并行性

现在,我们将综合介绍 D3D 12 的新特性如何在 PC 上创建真正的多线程游戏。 D3D 12 支持多个任务并行。 命令列表和绑定包可提供并行命令生成和执行。 绑定包可以记录重复使用的命令,并可在一帧或多帧内在多个命令列表中多次运行它们。 命令列表可跨多条线程生成,然后馈送至命令队列以便 GPU 执行。 最后,持续映射的缓冲区将并行生成动态数据。 D3D 12 和 WDDM 2.0 都针对并行性而设计。 D3D 12 删除了过去的 D3D 版本中的限制,支持开发人员以其理想方式实现其游戏或引擎的并行性。


图 21: 典型的 D3D 11 并行性,线程 0 执行大部分的任务,其他线程较少使用。

图 21 中的图表展示了 D3D 11 中典型游戏工作负载。 应用逻辑、D3D 运行时、UMD、DXGKernel、KMD 以及当前用途在一个包含四条线程的 CPU 上工作。 线程 0 执行大部分的任务, 线程 1-3 很少使用,仅在处理应用逻辑以及 D3D 11 运行时生成渲染命令时使用。 由于 D3D 11 的设计,用户模式驱动程序甚至不会在这些线程上生成命令。


图 22: 与图 21 的工作负载相同,但使用的是 D3D 12。 任务在 4 条线程上平均分配,而且借助 D3D 12 的其他效率,完成时间显著缩短。

接下来,我们看一下使用 D3D 12 处理相同的工作负载(图 22)。 同样,应用逻辑、D3D 运行时、UMD、DXGKernel、KMD 以及当前用途在一个包含四条线程的 CPU 上工作。 但是,该工作在所有线程间平均分配,并采用了 D3D 12 的优化特性。 得益于真正的命令生成,D3D 运行时能够并行运行。 借助 WDDM 2.0 中的内核优化,内核开销显著降低。 UMD 在所有线程上运行,而不仅是线程0,从而带来真正的命令生成并行性。 最后,捆绑包取代了 D3D 11 的冗余状态更改逻辑,并降低了应用逻辑时间。


图 23: D3D 11 与 D3D 12 并行性并排比较

图 23 展示了两个版本的并排比较。 借助真正的并行性,我们看到线程 0 和线程 1-3 之间 CPU 的利用率相对平均。 线程 1-3 执行更多的任务,因此“仅 GFX”显示提升。 此外,由于线程 0 上的工作负载降低,以及新的运行时和驱动程序效率,总体 CPU 使用约减少 50%。 再来看一下应用加 GFX,在各线程之间的分配更均匀,CPU 的使用约减少 32%。

9.0 总结

D3D 12 借助降低精细度的 PSO 提供了更高的 CPU 效率。 开发人员现在无需设置和读取每个状态,而是通过一个点操作,从而降低或全面减少了硬件失配开销。 应用设置 PSO,而驱动程序处理 API 命令,并将其转换为 GPU 码。 资源绑定的新模型消除了以前由于必须使用控制流逻辑带来的混乱。

借助堆、表和捆绑包,D3D 12 在 CPU 效率和扩展性方面都得到显著提升。 线性绑定点替换为应用/游戏管理的内存对象。 频繁使用的命令可以通过捆绑包进行记录并在一帧或多帧中多次播放。 命令列表和命令队列支持在多个 CPU 线程间并行创建命令列表。 现在,大部分的任务能够在 CPU 的所有线程间平均分配,从而充分释放了第四代和第五代智能英特尔® 酷睿™ 处理器的强大潜力和性能。

Direct3D 12 是 PC 游戏技术的跨越式发展。 借助更简单的 API 以及层级更少的驱动程序,游戏开发人员能够“接近完美”。 这提高了效率和性能。 D3D 开发团队通过齐心协力的合作,创建了一个支持开发人员控制的全新 API 和驱动程序模型,该模型支持他们创建更符合他们理想并具备出色图形和性能的游戏。

参考资料和相关链接

相关英特尔链接:

企业品牌识别 http://intelbrandcenter.tagworldwide.com/frames.cfm

英特尔® 产品名称 http://www.intel.com/products/processor_number/

声明和免责条款

请参见: http://legal.intel.com/Marketing/notices+and+disclaimers.htm

关于作者

Michael Coppock致力于 PC 游戏性能和显卡领域,自 1994 年以来一直任职于英特尔。 他负责帮助游戏公司充分发掘英特尔 GPU 和 CPU。 他主要关注硬件和软件,曾负责过许多英特尔产品,最早可追溯到 486DX4 Overdrive 处理器。

 

游戏公司借助英特尔® Sample Code 加速发展

$
0
0

下载 PDF

无论是独立的游戏开发人员还是以游戏开发为终身职业的游戏开发人员,都将受益于他人编写的代码。无论是对于了解新特性、解决以前难以攻克的问题,还是对于避免从头编写代码以节约时间,自由许可示例代码都是一种有益工具。英特尔在英特尔® 开发人员专区游戏开发人员板块提供了丰富的游戏示例代码。

Intel Game Developer Community Code Samples
1英特尔通过下列网址提供游戏示例代码:https://software.intel.com/en-us/gamedev/code-samples

过去几年,英特尔与许多游戏开发人员开展合作,帮助他们优化游戏在英特尔® 硬件上的运行性能。我们经常会提出重要见解或开发出卓越功能,它们应该以示例代码的形式与世界共享。有时,为充分满足开发人员的需求,我们会创建相应的示例。过去几年,我们创建的示例能够适用于 Blizzard 和 Codemasters 发布的游戏,例如自适应体积阴影图(Adaptive Volumetric Shadow Maps,简称 AVSM)、保守形态抗锯齿(Conservative Morphological Anti-Aliasing,简称 CMAA)以及 软件遮挡剔除 (Software Occlusion Culling)

AVSM 能够显著提升《超级房车赛:起点 2 (Grid* 2)》的运行性能

多年以来,Codemasters 与英特尔工程师一直在开展游戏开发合作。针对《超级房车赛:起点 2》,Codemasters 想方设法提高游戏在英特尔硬件上的视觉效果。他们与英特尔工程师们展开讨论,决定使用英特尔 PixelSync 特性增加烟雾真实感。该特性被认为可使赛车游戏达到高可视性效果,用户可借助它让赛车产生很大的烟雾痕迹。它源于英特尔工程师 Marco Salvi,他使用 DirectX 11 创建了 AVSM 实施方案,并在 2010 年的国际图形学年会 (Siggraph) 上对其进行了演示。英特尔示例代码使用原子操作确保无规则透明度 (OIT)。为了将该方案用于《超级房车赛:起点 2》,Codemasters 和英特尔工程师开展了合作,以使用 PixelSync 对算法进行修改,确保它可在有限内存中运行。有限内存中的AVSM修改版本也作为英特尔示例进行了发布。

Codemasters 和英特尔工程师开展了为期 14 多天的现场集成合作。当 Codemasters 得到了借助游戏本身的粒子效果来生成 AVSM 纹理和应用自阴影的工作测试层时,便可认为完成了初步实施。一完成初步实施,Codemasters 的工程师就可对系统进行扩展,以让动画纹理更好地匹配游戏画面和视效。同时,Codemasters 的艺术家设计了用于补充新技术的粒子效果,使用了大量更小粒子而非大广告牌来展示多种烟雾粒子。Codemasters 的工程师发现,改善的灯光效果会将用户的注意力吸引到加法混合 (additive-blending) 粒子系统中的排序问题上来,从而需要返工重新创建更可靠的 CPU 粒子排序。

在确保了出色效果后,工程团队还需寻找有可能在极端情况下发生的任何问题。由于该游戏支持受玩家控制的摄像头,因此该摄像头可能会因距离烟雾效果太近以至于屏幕布满烟雾。这会导致大量重绘,且 AVSM 示例无法对其进行处理。工程团队将 AVSM 与按照镜顶而非像素和灯光进行镶嵌的屏幕空间相结合。该新方法成功处理了大量重绘,以应对最糟糕的游戏问题。

英特尔示例代码在解决这种问题方面发挥了多种作用。最初的研究工作激励 Codemasters 添加新特性。于是,Codemasters 进行了修改,使示例更好地匹配他们的游戏。随后,英特尔更新并重新发布了经过改善的示例以供其他游戏开发人员使用。

Before and After Applying Intel AVSM Sample
2 Codemasters《超级房车赛:起点* 2应用了英特尔® AVSM 示例以达到更好的视觉效果

CMAA 使《魔兽世界*》的画面效果更加流畅

鉴于《魔兽世界》资料片《德拉诺之王*》可达到震撼的画面效果,Codemasters 将新抗锯齿算法添加到游戏图形选项。CMAA 用于为主流硬件提供快速有效的抗锯齿效果,是一种基于图像的后处理技术,由英特尔工程师 Filip Strugar 开发。通过在最后帧缓冲器上运行,它可在独立于渲染管线中其它变更的情况下实施抗锯齿。如《魔兽世界》某些最新延迟渲染技术所表明,该方法支持独立于所选明暗模型实施抗锯齿,为开发人员提供更多灵活性。

CMAA 还是一种可简单修改的算法,开发人员可自由地针对特殊用途对它进行修改并采取增强措施。《魔兽世界》6.1 内容补丁含有另一种名为 SSAA 2x + CMAA 的新抗锯齿模式。这样,通过在向下采样至原始分辨率之前针对 2x 帧缓冲对象实施 CMAA 计算,可将原始超级采样与后处理抗锯齿相匹配。通过算法组合可为高级用户提供最高保真度抗锯齿效果。

开发人员永远都是根据技术的开发价值而制定决策。就《魔兽世界》而言,由于英特尔提供了CMAA 示例,CMAA 试用决策的制定变得更加容易。该示例具有默认的测试场景,但仍允许开发人员插入自己的图像以预览 CMAA 效果并以毫秒计算分辨率或测量用例的增加成本,从而帮助开发人员制定成熟、明智的决策。《魔兽世界》开发团队可将当前 Pandaren 袭击内容的屏幕截图放入该示例中,并查看该性能成本下可达到多大程度的边缘平滑效果。

Intel CMAA Sample on a Custom Image
3英特尔® CMAA 示例具有默认场景,还支持在自定义图像上对效果进行测试

一旦决定好将 CMAA 添加至游戏,就需要对《魔兽世界》引擎做出某些更改,以支持 CMAA 使用的 DirectX 11 特性。虽然该技术成功地用于了渲染管线的尾端,但仍需以特定的方式准备数据。该算法需要有只读深度缓冲器视图,这意味着某些引擎可能需将可选的只读标志添加到纹理和帧缓冲器对象中。它的某些功能及性能还要依靠乱序访问视图 (UAV 又称 ImageBuffer)来实现。虽然很多 DirectX 11 引擎都实现了对 UAV 的支持,但其它引擎还需完成更新才能实现 UAV 支持。在这些支持加法之外,只对某些结构进行少许修改,就可几乎不加选择地对该示例的着色器代码进行重复利用。

CMAA 在成本价值和整体流程最小侵袭之间取得了重要平衡。这允许它以 90%-120% 的成本提供与 FXAA 3.8 相比更好的图像质量和稳定性。“增强型子像素形态学反锯齿” (SMAA) 是另一种受欢迎的后处理抗锯齿选择;最经济的版本 —— SMAA 1x 可提供更多抗锯齿功能,产生较少整体图形产品,但会造成更多的模糊及形状失真现象,且更易受到轻微帧间变化(短暂失稳)的影响,所有这些使它的运行成本与 CMAA 相比增加了 30%-120%。Leigh Davies 和 Filip Strugar 对这些算法的分析可用于 IDZ。

与 MSAA 不同,CMAA 的平滑功能还将能够用于 alpha 测试的纹理,为帧提供更加完善的抗锯齿。《德拉诺之王》甚至证明了,CMAA 可与 SSAA 相匹配,它所提供的抗锯齿效果与将它用于其他任何选项时相比,都更为美观和精确。该算法用于在 15W 第四代智能英特尔® 酷睿™ 处理器上以 1600x900 分辨率运行时,将时间保持在 3 毫秒以下。从算法复杂性角度来看,它的成本可按照 ½ 分辨率 3 pass + 1 最终原始分辨率 pass 来计算。

Blizzard&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;#039;s World of Warcraft uses CMAA
4使用 CMAABlizzard 的《魔兽世界》*能够在主流 PC 上实现顺畅的运行性能。

软件遮挡剔除可减少《魔兽世界》*中不必要的渲染工作。

另一个对《魔兽世界》具有吸引力的英特尔示例是软件遮挡剔除。通过仅渲染摄像头实际能够看到的物体,渲染时间大幅缩短,且几乎不会影响结果。Fabien Giesen 撰写了包含多个部分的博客系列,旨在分析英特尔示例(已经得到更新),且 Blizzard 认为它很好用。

如往常一样,该示例代码需要进行重写,以适合游戏引擎。Blizzard 工程师通过采用该示例的内核,独立构建了其余部分。2013 年 3 月首次实施时,整个遮挡流程仅耗费了 0.2 - 1.5 毫秒和较低成本。此后,它日益成为了该游戏中不可或缺的有益部分。

这些技术的使用帮助《魔兽世界》继续流畅运行,同时,Blizzard 增强了游戏的视觉效果,凭借主流硬件为用户提供畅快的游戏体验。自由选择全套机器可帮助工程师发掘新机会,而且情况已经在向好的方向发展。

英特尔® Sample Code 面向所有人

英特尔游戏示例代码团队竭力满足游戏开发人员的需求,并努力发现实际要求,构建可供所有开发人员使用的有效实施方案。英特尔® Code Samples 许可不会减慢您的开发进程,也不会妨碍您发布游戏。本文所举实例旨在表明英特尔开发人员专区的示例代码能够通过各种方式帮助提升游戏的图形保真度和运行性能。

参考文献

英特尔游戏开发人员社区 (Intel Game Developer Community) 中的代码示例 - https://software.intel.com/en-us/gamedev/code-samples

自适应体积阴影图 - https://software.intel.com/en-us/blogs/2013/03/27/adaptive-volumetric-shadow-maps

保守形态抗锯齿 (CMAA) - 2014 年 3 月更新 - https://software.intel.com/en-us/articles/conservative-morphological-anti-aliasing-cmaa-update

《德拉诺之王》中基于边缘检测的后处理(GDC 演示由 Blizzard 和英特尔® 实施) - https://software.intel.com/sites/default/files/managed/4a/38/Edge-Detection-based-Post-Processing-in-Warlords-of-Draenor.pdf

工程师研讨会:《德拉诺之王》中的引擎演进 - http://us.battle.net/wow/en/blog/15936285/

英特尔® Code Sample 许可协议 - https://software.intel.com/en-us/articles/code-samples-license-5/

基于像素同步的无规则透明度近似法 - https://software.intel.com/en-us/articles/oit-approximation-with-pixel-synchronization-update-2014

软件遮挡剔除更新 2 - https://software.intel.com/en-us/blogs/2013/09/06/software-occlusion-culling-update-2

 

作者介绍

Brad Hill 目前担任英特尔开发人员关系部门的软件工程师。Brad 负责调研关于英特尔硬件的新技术,并通过英特尔® 开发人员专区以及在开发人员会议上与软件开发人员分享最佳方法。此外,他还担任学生/独立黑客松的工程总监,负责为全美范围内高等院校的优秀黑客松/游戏开发活动 (gamejam) 提供代码运行支持。

John Hartwig 目前担任英特尔开发人员关系部门的软件工程师。John 主要负责与 PC 客户端和 Android 移动设备领域的游戏开发人员进行合作,实施优化和推出独特的硬件特性。John 于 2010 年加盟英特尔,最初担任 GPGPU 和媒体驱动程序的显卡驱动开发人员。他能够自己制作艺术玩具,并获得了德保罗大学游戏开发学士学位。

Viewing all 154 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>