关于WebRTC和移动端浏览器中的AR

之前有很多朋友问过AR能否不装APP而直接用浏览器打开使用,那个时候Android下踉踉跄跄,iOS不行,不行不行…渐渐的潜移默化的都直接跳过了这样需求,而无奈的选择了App支撑AR,也有很长一段时间我都是以”你要是在微信上看过的,那么就可以做,微信上没看过的,那么就是不能做或者说技术还不成熟”.自从iOS11中支持了WebRTC,意味着我们现在都可以在移动端的浏览器实现AR应用了,不过微信现在还不支持扫码后直接内嵌打开AR页面使用,因为微信的浏览器内核还不兼容WebRTC.

这是2017年6月的一篇文章:

WebRTC 开源 6 年遍地开花,“封闭”的苹果终于在 Safari 里支持了!
作者 | 唐门教主

在刚刚落幕的 WWDC17 上,苹果为我们带来了一个不小的惊喜 —— 其浏览器内核WebKit 将正式支持 WebRTC,而未来基于 WebKit 内核的苹果浏览器,比如 macOS High Sierra、iOS 11 中的 Safari 浏览器和 Safari 技术预览版 32,都将使用到 WebRTC 技术。

此消息一出便引得无数 WebRTC 开发者为之兴奋,更表示其将改变当前的 P2P 视频通话技术格局。这是为什么呢?在此,我们需要先简单地了解一下 WebRTC,其全称为 Web Real-Time Communication(网络实时通信),是一项能够让浏览器支持实时语音会话或视频对话的技术。这一技术前身为 GIPS,本是由 Global IP Solutions 公司研发,2010 年,Google 以 6820 万美元的价格将该公司收购并将 GIPS 更名为 WebRTC,次年 5 月正式将其开源。

彼时,我们所能想到的只是因为 Google 的推动,这样一项能够在浏览器内部进行实时音频和视频通信的技术让 Web 中的实时通讯成为可能。但同时,也有诸多开发者在质疑 WebRTC 是否会昙花一现,毕竟一直以来,虽然 Chrome、Firefox、Opera 等市面上主流的浏览器均已加入 WebRTC 大本营,但苹果的 Safari 和微软的 IE 却都不支持。

如今,Safari 即将在最新版本中集成 WebRTC,其对于整个实时通信领域而言,究竟意味着什么?对于 WebRTC 开发者来说,又将有着怎样的改变?我们带着种种疑问,请教了网络实时通信领域的资深专家 —— 声网 Agora.io 创始人兼 CEO 赵斌,从 WebRTC 的发展历程谈起,详细剖析 WebKit 终于支持 WebRTC 将带来怎样的变化。

追本溯源:为解决在浏览器上进行视频通话而生的 WebRTC

在 2011 年以前,浏览器之间要想实现实时通信,需要私有技术,其中大部分都是通过插件和客户端来安装使用。对于许多用户而言,插件的下载、安装和更新是一个复杂、繁琐和容易出错的操作。而对于开发人员来说,插件的调试、测试、部署、错误修复和维护同样困难重重,且不提还涉及到一些受版权保护的技术,整合相当复杂。再者,很多时候,服务提供商很难说服用户去安装插件。

但这一两头吃力还不讨好的局面就这样被 Google 将 WebRTC 项目开源所打破。2011 年,WebRTC 基于 BSD 协议开源,同年,W3C 启动 WebRTC 计划,让 WebRTC 成为了 HTML5 标准的一部分(目前,该规范还在开发中)。

由此,浏览器厂商将 WebRTC 内建在浏览器中,使得 Web 应用研发人员能够通过 HTML 标签和 Java API 即可实现 Web 音视频通信功能。在 WebRTC 的官网上,Google 如此表述道:

互联网成功的关键因素之一,便是一些如 HTML、HTTP 和 TCP/IP 等的核心技术是开放和免费实现的。目前,在浏览器通信领域还没有免费、高质量、完整的解决方案,而 WebRTC 正是这样的技术。

该技术包含了使用 STUN、ICE、TURN、RTP-over-TCP 的关键 NAT 和防火墙穿透技术,并支持代理。通过浏览器,WebRTC 把通讯双方的信令状态直接映射到 PeerConnection 里面来抽象信令处理,这样,开发人员按不同的应用场景选择不同的会话协议,比如 SIP、XMPP/Jingle 等。截至目前,该技术的使用已经超过了 8 年,集成了最佳的音频、视频引擎,并被部署到数以百万的终端中,同时这些技术 Google 不收取任何费用。

从最初的为了解决浏览器上视频通话而诞生,WebRTC 已经发展到可以实现在浏览器之间进行任意数据的通信。其中,Chrome、Firefox、Opera 对于 WebRTC 的支持已较为成熟,而微软于 2014 年提出了 ORTC(对象 RTC,也有人称之为 WebRTC 1.1),希望在对 Google 的 WebRTC 提案稍作修改的基础上,也提供支持。目前,最新版本的 Microsoft Edge 已经支持 ORTC。

而对于苹果官方终于宣布“WebRTC 将在 Safari 11 上支持”,赵斌如此评价道:“目前,WebRTC 已经有了 1.0 版本,暂时还是草案。但是我们可以看到的是,WebRTC 在网络抗丟包处理、视频引擎(比如 H.264 Codec 支持成熟度)等方面,还是需要加强的。1.0 之后的 1.1 版本,考虑到了和 ORTC 的结合,让 WebRTC 可以在微软浏览器上实现,这是 Google 和微软同时推动的阶段性进展。实际上,Google 的 WebRTC 从一开始的计划就是能支持所有的主流浏览器。之前最大的障碍是微软浏览器和苹果浏览器,但是通过 Google 的推动,这些实际上都在发生变化。而 Safari 在 iOS 11 中将支持 WebRTC,既是行业里最后一个重要的浏览器加入这一潮流,也是这一进程的重大胜利。这在 WebRTC 的发展上是里程碑性的事件,将会极大地推动 RTC 技术在各种应用网站上的普及。当然,目前苹果对 WebRTC 的支持还比较粗糙,需要更多的时间成熟,并解决互通上的更多问题。微软则还需要在标准的一致性上参与行业的讨论,缩小和拉近在互通性方面的差距。”

那么,Safari 终于实现对于 WebRTC 的支持,究竟意味着什么?

一直以来,WebRTC 开发者总被一个无法逃避的阴影所笼罩,那就是来自用户的“什么时候微软和苹果的浏览器支持呢?”的疑问,每每此时,却只能给出让用户使用 Chrome 和 Firefox 的解决方案。而在移动端,事情变得更加复杂,因为在 iOS 上,使用原生是唯一的办法,也由此增加了 Swift/Objective-C 的开发成本,尽管 React Native 能够构建支持 WebRTC 的 Android 和 iOS 应用让这一状态有所改善,但却无法从根本上解决问题。

而随着支持 WebRTC 的 iOS 版 Safari 的到来,意味着开发者们可以提供一个在 Web 端、移动端均可运行的响应式网站来实现 WebRTC 通话。对于开发者个人而言,也无需为了完成项目而绞尽脑汁地成为 Objective-C、Swift 或 React Native 方面的专家,通过 Java 即可实现这样一个精细复杂的网络电话应用,由此开发成本将得到大幅降低。

在谈到 WebRTC 移动端实现时,赵斌表示:“在 Safari 支持 WebRTC 后,过去只能在诸如 Chrome 浏览器之间实现的音视频通话,现在在 Safari 以及 Chrome 与 Safari 之间实现了,其影响一定是积极的。可以预见,很多网站及开发者将会更加认真地考虑将这类功能添加至网站及应用中。”

仍有缺憾:WebRTC 应用已遍地开花,但为何大规模单纯使用的成功产品却少之又少?

尽管 WebRTC 应用已经如此广泛,但其也并非完美,比如在稳定性、P2P 连接率、呼叫成功率、网络抗丟包性能等诸多方面,都还有很大的提升空间。所以到目前为止,大规模单纯使用 WebRTC 成功的产品还是凤毛麟角,且几乎都是在网络和设备性能非常成熟的美国,比如 Facebook Messenger、Google Hangouts。

且 WebRTC 是基于浏览器上的技术,大部分都是在浏览器中应用。而使用 WebRTC 在移动端上进行开发,差别还是很大。虽然可以实现,但门槛会很高,难度也会很大。对绝大多数开发者来说,要用 WebRTC 在移动端实现良好体验,不是一件容易的事情,会遇到非常多的坑。在进行 WebRTC 开发之前,开发人员及其团队需要根据自身的情况,来决定是自主开发还是使用第三方 SDK。

对此,赵斌与我们分享了他的经验:“实时通信是一项实现功能容易,但做好很难的技术。我曾在 WebEx 和 YY 工作将近 20 年,非常清楚 RTC 技术的坑。也知道对于一个开发者而言,要自己在 App 和浏览器中实现实时音视频通话,是非常麻烦且累人的事情。很多开发者最容易掉进的坑,就是忘了如果想要用好实时通信技术,归根结底还是在于使用过程中的质量保障,而非研发时写的那些功能代码。”

也正因如此,赵斌和他的团队对 WebRTC 在质量保障方面进行了扩展,比如为了解决 WebRTC 在弱网络环境下抗丟包、通话连通率等问题,在全球部署了虚拟通信网 SD-RTN™(Software Defined Real-time Network),有近 100 个数据中心,同时,为开发者提供一个极简 SDK,帮助其在任何 App、网站上,都能实现高质量的音视频通话、全互动直播。据赵斌介绍,目前这款 SDK 已经被嵌入到了超过 5 亿的终端设备上,仅仅花了1年左右的时间,全球范围内对于实时通信质量保障的强烈需求可见一斑。

总结:实时通信技术无所不及的应用场景

WebRTC 一直是推动 RTC 实时通信技术发展的最主要力量,让实时通信技术能够在互联网很多行业里得到广泛应用。而近两年来,我们也看到了实时通信技术在很多领域正在驱动非常多的创新应用场景,比如去年大热的互动直播,主播与观众随时连麦互动、不同房间的主播连麦聊天等,以及当下正在流行的狼人杀,包括语音、视频甚至是轮麦视频狼人杀,这些场景都是基于 RTC 创造出来的。另外,在 AR/VR 和 AI 等新技术领域,也有诸多结合,如视频通话时的动态滤镜贴纸、戴 VR 眼镜和虚拟世界里的朋友聊天等等。当然,对于传统行业,比如企业协作、金融、客服等领域,都有可能借助 RTC 技术打破地域界限,让更多人可以做居家客服、居家办公 SOHO 等。

“我们认为,随着 WebRTC 被几大浏览器统一支持,应用的成长和发展是必然的。未来,无论在怎样的场景下,实时通信都会成为人们的一个默认选择,无限缩短人与人之间的距离。而用户会越来越多地了解和熟悉这种使用模式,开发者也会越来越多地理解其中的门槛,以及质量保障在实时通信领域的价值。”最后,赵斌如此总结道。

AR中的阴影镂空,蒙板处物体遮掩,蒙板处物体显示等

我们在做AR(增强现实)的时候,有几种效果需求会遇到.

1:阴影镂空
通过成功识别Marker(花朵背景),在Marker位置生成立方体模型,为了效果逼真,我们需要立方体模型产生个阴影投影,默认情况下我们只能用其它模型来接受立方体的阴影投射,Marker模型在Play时是不能用于接受立方体阴影的,我们把接受阴影的Plane模型进行处理,让它仅保留投射的阴影部分,其余部分镂空,这样再与相机画面叠加就会产生一个较逼真的阴影效果了.

把下面的shader赋予给接受阴影的模型即可完成阴影透明镂空效果,图中黑色阴影其实是原本的Plane,与Maker无关.

Shader "FX/Matte Shadow" {
 
Properties {
    _Color ("Main Color", Color) = (1,1,1,1)
    _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
}
 
SubShader {
 
    Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
    LOD 200
    Blend Zero SrcColor
 
CGPROGRAM
 
#pragma surface surf ShadowOnly alphatest:_Cutoff
fixed4 _Color;
struct Input {
    float2 uv_MainTex;
};
inline fixed4 LightingShadowOnly (SurfaceOutput s, fixed3 lightDir, fixed atten)
{
    fixed4 c;
    c.rgb = s.Albedo*atten;
    c.a = s.Alpha;
    return c;
}
 
void surf (Input IN, inout SurfaceOutput o) 
{
    fixed4 c = _Color; 
    o.Albedo = c.rgb;
    o.Alpha = 1;
}
 
ENDCG
}
 
Fallback "Transparent/Cutout/VertexLit"
 
}

2:蒙板处物体遮掩

黄色模型为蒙板,其它模型凡是被蒙挡的地方都不渲染,就像布尔减去黄色模型一样,这个效果可以用来做什么呢?比如说做了人脸识别,要给相机图像中的角色戴副眼镜,如果没有用蒙板遮挡,那么无论相机画面里是侧脸还是正脸都将看到完整的眼镜,这与现实不符,现实中侧脸的时候我们只能看到视距较近的眼镜腿,另一侧眼镜腿应该被脸部遮挡,而我们取的相机画面,它是2D平面的图像,不能自动帮我们进行正确的显隐,所以我们要做一个适当的头部模型作为裁切蒙板即替代黄色模型来把不应显示的部分遮掩掉.

只需将下面的shader作为材质球赋予给希望作为蒙板的模型即可.

Shader "DepthMask" {
   
    SubShader {
        // Render the mask after regular geometry, but before masked geometry and
        // transparent things.
       
        Tags {"Queue" = "Geometry-10" }
       
        // Turn off lighting, because it's expensive and the thing is supposed to be
        // invisible anyway.
       
        Lighting Off

        // Draw into the depth buffer in the usual way.  This is probably the default,
        // but it doesn't hurt to be explicit.

        ZTest LEqual
        ZWrite On

        // Don't draw anything into the RGBA channels. This is an undocumented
        // argument to ColorMask which lets us avoid writing to anything except
        // the depth buffer.

        ColorMask 0

        // Do nothing specific in the pass:

        Pass {}
    }
}

3:蒙板处物体显示

这个蒙板默认情况下会将它所覆盖的所有对象都裁切掉,可谓杀的毫无痕迹,如果我们用Unity内置的相机纹理贴到模型上作为图像背景的时候,它同样也会被蒙板扼杀掉,而我们不喜欢它被挖空,所以要针对它进行处理,让这部分不受蒙板影响.

把下面的脚本挂接到任何不想被蒙板影响的对象上,如我们挂到蓝色模型上,脚本有个暴露的变量,我们将RenderQueue设置比蒙板shader的RenderQueue数值小的值,在Play时,蓝色模型就可以无视蒙板.

using UnityEngine;

[AddComponentMenu("Rendering/SetRenderQueue")]

public class SetRenderQueue : MonoBehaviour {

	[SerializeField]
	protected int[] m_queues = new int[]{3000};

	protected void Awake() {
		Material[] materials=this.GetComponent().materials;
		for (int i = 0; i < materials.Length && i < m_queues.Length; ++i) {
			materials[i].renderQueue = m_queues[i];
		}
	}
}

资料参考:
http://mec0825.net/blog/?p=126
http://wiki.unity3d.com/index.php?title=DepthMask