Unity涂色AR教程(一)

前言

注意啦!本涂色代码在Vuforia5以上版本失效了!

  上学期在公司实习接触到了AR,使用的Metaio的SDK,这家公司最近悄悄地被苹果收购了。然后可以看到最近各类AR产品出现,都显示着一种趋势。不过说实话,现在的”AR”局限依然很大,现有AR产品大多都是面向低龄的儿童产品,同时也依赖手机设备和固定的标记图。

  近来出现的涂色AR是一个不错的新的玩法。功能依赖Shader和代码一起工作,而原本的Shader是一个Unlit的无光照无投影的Vertex Pragment Shader,效果不是很好。昨天晚上照着几篇博文,给这个Shader添加了光照和投影,基本得到了Diffuse的效果。

这篇不涉及高通AR的基本用法和操作,没有用过高通AR的最好还是先补习一下。

实现原理

AR的基本原理不多说了,主要就是标记图片的识别和追踪。

说一下拾取涂色的原理:

  • 首先识别到图片
  • 调整相机位置让完整的标记图片出现在相机画面中
  • 获取相机的画面
  • 把上面获取的画面作为贴图贴到模型上
  • 模型上的脚本会利用Shader和代码根据一个贴合标记图透明Quad计算出相机画面中正确的贴图位置
  • Duang!

制作流程中的要点:

  • 先画标记图再做模型,分UV时把标记图贴到模型上根据标记图把UV塞到空白可以涂色处
  • 标记图的线条不要太细,至少每个物体用粗线条描个边
  • 物体画偏侧面的角度对UV的拉伸较小,效果会比较好
  • 涂色推荐水性材料,油画棒等容易遮挡线条可能导致涂色后难以识别
  • 也可以在周围画一些识别性能强的辅助物体,不做拾色用途但可以增强识别性能

UnityPackage下载

ColorAR-Gypsum.unitypackage

提取码:2ef0

这是旧版,新版请看后面的文章。

  • 包括了Vuforia4的SDK,如果已经有了则只要导入ColorAR-Assets文件夹就可以了
  • 里面包含了一个Example场景

注意:只能运行在移动平台上,相机画面拾取的功能无法直接在Unity内调试,为什么我也不知道。

开始

导入资源包后,你可以打开ColorAR-Assets/Example文件夹中的场景,打包导出到手机平台(IOS/Android)试试效果。

一些坑:

  • 如果没有投影,请尝试在Quality设置里调整阴影距离等参数
  • Android(一般是5.0以上)如果遇到无法安装,在Player Setting的Other Setting中Install Loacation改为Automatic

标记图为ColorAR-Assets/Example/Cube-Target,你可以用PS等软件打开并随意在方体表面上涂写,效果应该是这样的:

Screen-Shot

如何用在自己的项目上

  实现原理之前已经写了,相应的Shader为CameraTargetPatchLighted,你需要新建一个Material并使用这个Shader,将你需要使用拾色贴图的模型换上这个Material。相应的脚本为CameraImageAccess,同样也要绑到之前的模型上。

  此外,新建一个Quad,使用CatchUV这个材质,Quad拖到ImageTarget下成为子物体,然后调整Quad的Scale,使其尺寸完全贴合ImageTarget标记图。然后把这个Quad拖给之前模型挂上的CameraImageAccess的QuadCatchUV。

  之后你需要调用CameraImageAccess的UpdateTexture()才能更新贴图,一般的逻辑自然是在ImageTarget的TrackableEvent中的OnTrackingFound()里调用。如果你不熟悉,可以直接使用我写好的ExtendTrackableEvent,挂在ImageTarget上。这个脚本会在识别到图片之后默认延时1秒钟再拾取相机画面,并有UI指示,原因是手机在移动过程中识别到之后立即拾取画面很容易导致模糊,出来的贴图自然也是模糊的,有延时可以让画面更稳定。延时可以在脚本的Inspector里修改,不要忘记给Loading Ring赋实例,在Prefab文件夹里有我预制的一个Canvas Loading,拖到ImageTarget下,适当缩放,把Canvas Loading子物体的Ring拖给脚本的Loading Ring。这样你的项目应该就可以实现Example中的效果了。

  如果出现了问题,请参考Example场景尝试修复。

  • 注意:如果你的模型有很多组件且没有Combine,你就需要在每个模型组件(Renderer)都绑上一个CameraImageAccess。这样性能非常差,因为每个组件在更新贴图时都会走一个完整的拾取画面并计算贴图的流程,但是代码是可以优化的,思路可以是:拾取相机画面只运行一次,然后把贴图传递给每个组件(Renderer),再让组件分别自己计算贴图。如果觉得不能实现,还是请在Maya等软件里把没必要拆分的模型都Combine一下吧。

关于投影:

  • 现在的CameraTargetPatch支持光照和阴影了,你可以添加一盏Directional Light并开启阴影
  • 由于Unity的AR开发中,单位都会比较大,所以你需要在Quality设置里大幅增加阴影距离可能才能会看到投影效果

使用普通的Plane来接收阴影,会导致面板遮挡实景画面,这不符合AR思路,效果也不好。所以我们需要一种:

本身是透明的,但是却可以接收阴影的Shader。

ColorAR-Assets/Shader文件夹中Matte Shadow就是这样一个Shader。

关于遮挡

遮挡应该是AR中比较重要的一个特性,通过遮挡住模型的一部分可以模拟现实中的遮挡关系。

需要修改Shader中Queen(渲染队列)实现,这个东西非常适合AR,可以实现很多神奇的效果。

这次的包中没有包含这个内容,让我再学习下Shader,待续。