Unite大会, 连续四届成功 (2015~2018)

2018年Unite大会, 5月13日在北京国家会议中心(鸟巢)闭幕。

做为从业者,我已经连续参加了4次Unite大会,期间身份也多次转变,从行业新手到熟人社交圈子,期间点点滴滴,可谓多多。

Unite大会,目前已经上升到国内最密集技术的高峰技术干货会议,没有之一。
以Unity3D引擎技术为主导,涉及游戏、VR、AR、MR、BIM、教育行业技术、产品、生态圈企业构成。 

 

以今年Unite大会为例,Unite不仅仅手游引擎领域依然霸主,同时在MR领域,也是崭露头角,如今年整个有超过6个Session是关于MR的,还有2个关于BIM Session,可见Unite多元化发力多多。

NewImage

火热的游戏《旅行青蛙》,就是基于Unity3D制作的,而且,就1个U3D程序员,还是从Objective-C程序员转过来的,大约用了半年时间,UGUI技术用的比较多。

可见,U3D上手能力是非常快,特别适合这种小型化团队,如旅行青蛙团队4个人(一个策划、一个产品经理、一个美术、一个程序)。

 

NewImage

因为工作关系,我比较关注MR,尤其是和工业、IOT结合的Session比较符合当下我抓的方向。

本次活动的MR,核心是围绕目前MR设备最成熟的HoloLens设备展开的,如解放双手、结合IoT、提高生产效率等等,这些解决了企业当下的实际痛点,市场空间还是比较大的。

 

下面,分别通过几张照片,回顾一下2015~2018年Unite大会:

———————————————————————————————————–
2015年 Unite大会 北京

NewImage

当时的心得记录:

网友见面会的最高法则,记着网名就行,真名非常容易和网名之间混淆。可惜,我连个网名都没有 。
手机的拍照功能真的重要-如抢拍、合影留念、远距离拍照PPT做笔记等。
各大企业市场推广,几乎放弃微薄,目前微信服务号和朋友圈是企业几乎唯一的营销方式。
IT垂直社区在崛起,老资历的综合类IT社区在打烊,如微软TechEd大会去年最后一次后,今年已经关闭。
社区的灵魂是人情味,温度是外在的表现。再次感谢蛮牛游戏优弧亲自电话给我导航,担心我在北京迷路
Unity公司,是近年国际巨头公司罕见的重视大中华区的公司,其创始人和副总们专程从美国飞北京参会。
接地气的中国梦,多年前人才观是名校、高学历、外企;如今更看重个人才华、勤奋、汗水、创业公司
多和正能量的朋友交流,假以时日,你必获益。如种下一颗种子,先勤劳的浇水、锄草、施肥。
年轻真好。稚嫩的身影,18、19岁,千里迢迢的,自费参加技术大会,我已经看到了多名未来的星星们。

 

2016年 Unite大会  上海

NewImage

第二次参加Unite大会,换到了上海,这个Session印象比较深刻

 

2017年 Unite大会 上海

NewImage

Unite,再一次上海了。

 

上面合影是UUG负责人:从左往右依次是杭州UUG负责人、北京UUG负责人、UUG掌门人玥姐、me、上海UUG负责人、天津UUG负责人。

2018年 Unite大会 北京
NewImage

今年,终于回归北京了,参与北京社区人气旺一些,而且在国家会议中心,气势更宏大。

 

2018 荣获Unity UVP专家称号

NewImage

出乎意料,获得了首届Unity认证的技术专家:当日发的朋友圈的感悟—既是荣誉,更是责任。

加强社区、加强技术分享,传播正能量。

 

Unite 2019,加油,加油!

微软.NET年芳15:我在Azure上搭建Photon服务器(C#.NET)

    网上火热的“微软.NET年芳15”文章,我也得写点什么嘛,毕竟我还是现任的微软MVP

image

 

摘录网上的“.NET 15周年”信息如下:

微软的 .NET 框架本周迎来了 15 岁生日。.NET 的第一个版本在 2002 年 2 月 13 日作为的 Visual Studio.NET 的一部分首次公开亮相。过去 15 年,.NET 框架从一个流行的闭源软件开发平台,变成了一个开源的跨平台开发工具,微软是在 2014 年 11 月 12 日宣布开源 .NET,支持竞争对手 Linux 和 OS X 的平台。微软称,Visual Studio 2017 将于 2017 年 3 月 7 日发布,而 Visual Studio 也迎来了 20 岁生日,开源的 .NET Core 也将发布 2.0版本

 

      我梳理了一下目前的.NET技术栈: 业务是基于Unity3D(跨平台游戏开发引擎),开发AR、VR 应用; 绝大部分项目采用单机版,使用的编程语言是C#(Mono.NET),不过最近交流的AR几个业务,明显用户已经不太满足单机版,有更多的需求需要用到联网的服务器功能,故技术选型就势在必行了:也算是未雨绸缪吧。

 

技术栈选型

我的技术选型有2点原则

  1. 成熟,有助于提高开发效率
  2. 人多,有坑大家一起填

这2点原则是基于第一次创业失败的经验总结。约在3年前吧,刚开始创业的时候,特别排斥C#.NET技术(互联网创业,还用C#,说出去都不好意思啊),虽然用的是Unity3D游戏引擎(C#),但是服务器选择却是非.NET倾向的。 那个时候对比了多种技术栈:

  • PHP游戏服务器
  • Node.js游戏服务器
  • C++游戏服务器
  • JAVA游戏服务器

权衡再三选择是Java,采用的是SmartFoxServer商用服务器框架,JAVA和C#非常类似、学习成本低一些。

种种原因,后来呢,第一次创业失败了,我的反思是“创业成功大部分原因是CEO的引导有方,创业失败大部分原因是CTO的选择失误导致”。

当时我没有考虑到成本意识、对一个5人研发团队,C#、Java并行的沟通风险有多大:

如果当时客户端是C#技术栈、服务器端也是C#技术栈,则可以从5人技术团队裁掉1人,节约20%人力成本,而且减少沟通后可以提高30%的开发效率,进而有效的推动产品快速扑向市场的速度,可惜这个是“事后诸葛亮”。

这个“事后诸葛亮”,我一直如噎在喉.

       不过去年在一次微软技术峰会,看到网易案例的演讲,我的眼睛亮了起来:“微软技术大神徐玉涛Tory做的分享—网易《绝代双骄》将游戏后端从Java转为新一代.NET Core,研发效率提升20%,服务器成本节省50%”–在线视频为证。

 

故对选择一款C#的服务器,以打通AR、VR客户端、服务器端,提高开发效率,生产力加速,我个人非常期待

Photon

商用

成熟

C# (Mono.NET)

ASP.NET Core

开源

 2.0还未发布

.NET Core

Unity Network Unity自带 局域网

C# (Mono.NET)

有SmartFoxServer的实践经验,故雷同的商用服务器Photon我本次做了专门的实践.

Photon支持3种类型服务器

  • LoadBalancing: 负载均衡服务器
  • MMO: 大型MMO网游服务器
  • Lite: 大厅、房间类型服务器 (相对简单一些)

Photon授权策略:免费版100个CCU (对于绝大部分AR、VR项目足以了);  商用版3500美金不限制CCU (约2.5万人民币)。

image

 

云服务器选型

我的选型原则也就2点:

  1. 速度:国内访问速度快、快、快!
  2. 便宜:方便我们这种初创型公司节约不必要的成本

虽然同样是世纪互联在运营,但是早期的AZure在我心目中,网速那是非常非常的慢、价格也是高高在上(和国内的阿里、百度等云比起来,毫无优势可言),故原来使用过阿里云、七牛云,国际版高大上的AZure和AWS都未曾考虑过。

但是呢,微软MVP内部微信群、邮件组,AZure的讨论还是很多的,尤其是“自2017年2月1日起,Azure虚拟机价格大幅下调,最高降价幅度高达60%!”这则消息讨论了好几天,我也渐渐回头持续关注AZure。

通过信息搜集,我了解的AZure信息碎片如下:

Windows Azure在北京、上海部署有服务器

中国的AZure是个”国内版本”–和国际版AZure采用物理隔离方案

MySQL也是比较符合目前国内接地气的方案;

AZure新的特效,国际版和国内版部署时间约差不多是3个月至半年。

https://www.azure.cn/  是国内版本的网站

 

在Azure上搭建Photon服务器(C#.NET)

image

 

未来AR产品软件框架是这样的,服务器端需要搭建游戏逻辑Photon、以及资源更新AssetBundle–更新资源。MySQL目前是国内很多公司的标配–社区版免费。

 

image

Photon运行方式很简单,选择服务器实例,启动应用即可,符合GUI操作习惯。

 

image

AZure虚拟机,提供了C盘,直接把需要的软件和数据,通过远程桌面拷贝过去即可,windows Server 2012英文系统,还是挺方便的。

 

几个有用的小技巧:

  • TT模板:database first–自动生成模型代码

原创文章来源: 使用T4模板生成MySql数据库实体类

注意在VS2015下,需要把.ttinclude后缀修改为.tt才可以。 同时,需要修改 数据库连接为你自己的 9 var connectionString = @"server=127.0.0.1;uid=root;pwd=12345678;charset=utf8;";

AZure开5505 UDP端口

  • 前端、后端C#链接类快捷方式:节约成本的王道

image

即,直接可以实现前段和后端复用模型实体代码、传递的Code枚举代码,以减少文档重复工作量。

以关键的OperationCode为例,如果前端是C#、后端是Java,则无法做到代码级别复用,即需要写文档来约束。而相同的C#代码后,注释好.cs文件,前端和后端是同样的代码,则沟通起来畅快了很多。

public enum MyOperationCodes : byte
    {
        /// <summary>
        /// LoginOperation
        /// </summary>
        LoginOperation = 100,

        /// <summary>
        /// EchoOperation
        /// </summary>
        EchoOperation = 101,

        /// <summary>
        /// GameOperation
        /// </summary>
        GameOperation = 102,

        /// <summary>
        /// ChatOperation
        /// </summary>
        ChatOperation = 103,

        /// <summary>
        /// ChatOperation
        /// </summary>
        CCUOperation = 104,
    }

  • MySQL ORM (Dapper框架):

    我选择了轻量级、火热的Dapper(stackoverflow网站就用它来做ORM),而且开源。 image

    使用SQL部分代码如下:

Db aa = DbInit();

 
var a3 = aa.Query<device>("select * from device where uuid=@uuid", new { uuid = "aabb636238694579824398" });

 

device dv = new device
{
     UUID = "aabb" + DateTime.Now.Ticks.ToString(),
     DeviceModel = "IOS",
     DeviceName = "Iphone 5s",
     RegisterDate = DateTime.Now.AddDays(-1),
     UpdateDate = DateTime.Now,
     TokenID = DateTime.Now.Ticks.ToString()
};
long ret = aa.Devices.InsertOrUpdate(dv);

var a1 = aa.Devices.All();

    • Json序列化工具:newtonsoft

    本来Unity5.3已结自带了Json序列化API,但是有bug,Json序列化可能为空,就选择了”老朋友”newtonSoft.dll了。

    • AZure开通端口
    • 应用跑起来后,端口一直不通,需要AZure开通端口–首先在Windows Server里面开通端口(TCP\UDP),然后再AZure里面开通:网络接口–网络安全组–入站安全规则、出站安全规则。

     

     

    PhotonLab 源码:https://git.oschina.net/xifarm/PhotonLab

     

    参考

    1. 时间飞快–连微软官方都开源了208个源码库
    2. 岁月在挑灯夜战中走过:亲历的软件框架
    3. 我的微软.net演进路线图
    4. 荣获2015微软.NET MVP称号!
    5. 写在.NET 15周年之际——致那些仍然爱着.NET的中国程序员们 来自微软MVP Tony Qu微信
    6. .NET 十五岁,谈谈我眼中的.NET 来自微软MVP  张善友的博客》

    Unity User Group 北京站图文报道:《Unity3D VR游戏与应用开发》

         很高兴,能有机会回报Unity技术社区:我和雨松MOMO担任UUG北京站的负责人, 组织Unity技术交流和分享活动。

    image

    本次北京UUG活动场地–微软大厦

    image

    成功的UUG离不开默默无闻的付出:提前2小时到场的志愿者

    image

    雨松走到那里, 都会有Unity3D 粉丝合影

    image

    UUG活动正式开始,  雨松首先上台致辞

    image

    什么是 Unity User Group?

    Unity在西安、南京、厦门等全国所有城市招募UUG领袖啦! 作为Unity User Group的组织者,我们希望你:

    • 热爱Unity, 热爱开发,愿意与更多Unity开发者分享这份热爱。
    • 有号召力,擅长组织线下活动,为本地的Unity开发者提供定期交流的平台。

    根据各地区UUG的活跃情况,Unity将为UUG组织者授予官方的UUG荣誉头衔,并根据UUG运营的实际情况为高质量的UUG活动提供相应的资源与宣传支持。

    如果你认为自己能胜任地区UUG领袖,请将简历以及相关的活动组织经验发送至:uugchina@unity3d.com

    王世元 分享的话题《TVR的游戏研发与设计之路》

    image

    议题简介:使用Unity开发VR游戏的优势;从《再现甲午》、《星际穿越》、《Ace Banana》、《MIXIP》、《FlndingVR》的简介、游戏风格、游戏交互方式以及VR特性的利用进行经验分享。

    image

    周日下午, 200人的场地坐的满满的

    王明杨 分享 话题《使用Unity开发一个虚拟影院》

    image

    议题简介:通过一个移动VR影院的范例介绍Unity中将视频作为Texture的原理,在VR中开发沉浸式观影体验。

    image

    制作VR虚拟影院的4个步骤

    潘博航 分享 《虚拟现实交互设计》

    image

    议题简介:从交互设计角度探讨VR内容设计。将阐述Unity开发者目前阶段可能遇到的问题和限制,以实际的案例经验总结探索 VR 内容的交互形式和未来的可能性。

    image

    大家耳熟能详的的VR消费级输入设备:HTC Vive、Oculus、PSVR

    image

    《2016,VR元年》:你们是规则的制定者!

    北京UUG合影留言

    image

    北京站大合照来一张。前排好多美女.

     

    北京UUG部分花絮

    image

    开心的抽奖环节

    image

    为你的热情点赞: 专程从天津赶到北京参加UUG活动开发者。

    image

    Unity官方小礼品–人手一份

    image

    坐在第一排的某童靴的笔记—好认真啊。

    image

    会后部分讲师和UUG组织者合影,从左到右:潘博航、宣雨松、王明杨、王文刚刘玥

    一个女学生,对Unity特别感兴趣,摘录自她分享的朋友圈:

    “我是个门外汉,Unity刚入门,听起来有点吃力,但是,我觉得今天UUG最大的亮点就是分享的内容比较多比较丰富,特别是最后那个哥们分享了很多听起来很牛的东西,虽然我啥都没听懂。

    但是感觉应该很实用。

    参加UUG,  没错,下次活动还要来。”

    备注:

    Unite ShangHai 2016 (Unity3D开发者大会)

         拜Unite ShangHai 2016 大会所赐,又一次来上海–上次来上海是2007年做TD-SCDMA扫频仪数据接入工作的; 一晃,9年过去了,上海变化挺大的。

     

    上海.印象

    10号起来,在附近溜达溜达,静安公园、蔡元培雕像

    imageimage

    路过了约3公里上海街区,周日上午都8点半了,马路上人很少且干净,还是上海人小资啊。

     

    晚上和杭州赶来的某著名物联网公司CTO胡键,一起共进晚餐,顺道吹吹牛。

    我们两人4年前是在西安OpenParty认识的,后来一起组织西安的IT活动,如《“西安IT人的社交圈”11月的活动总结》。   近半年,无独有偶,在“万众创业、大众创新”的时代,他从西安出走,带队来杭州专注物联网行业创业; 我则选择离开西安,在北京专注VR。

     

    上海人过马路很讲规矩:通过红外线检测,然后声音警告行人站在台阶上

    image

    这一点,值得赞,可以极大加速路口车辆通过; 还可以保障安全

     

    上海豫园–城隍庙街区

    imageimage

    其中:左侧图片的西洋镜(拉洋片),这个小玩意算是中国最早的VR虚拟眼镜了吧。

     

    Unite 大会(KeyNote)

    上海是周一KeyNote大会,明显人数较去年北京活动少了很多,还是Unite换了新的CEO,控制成本吧。

    参展商也少很多,估计是北京的1/5参展商规模, 且会场外空间相对比较小,不利于排长队进行体验.

    image

     

    Unity 5.4 VR性能优化增强30%

    imageimage

     

    Cinematic Image Effects 电影CG渲染效果—Realtime

    image

    image

    这个案例的亮点是连保守的日本marza工作室都用起来Unity做CG动画电影,间接反映出Unity在图像处理上面往AAA级画质发展的雄心和实力。

     

    Unity大中华区核心工作:服务支撑

    image

    就我个人经验而谈,网速才是服务背后的支撑。如Asset Store下载插件,很慢。

    另外,听说官方也在搞Unity中文版。这个需求,我个人倒不是特别想要–少bug、性能提升更关键。

     

    Unity Labs:Unity法国的精英团队。

    image

    最近在聚焦VR中设计VR场景(VREditor):人带上VR头盔,用Touch手柄进行VR场景编辑。

     

    VR(虚拟现实)火热依旧–2016

    4.10号  VR有一天时间培训课,400+人参加

    4.12号 全天有VR重点技术课程,2000+人参加

    而整个Unite 大会才3天,从时间上看,2/3在谈论关于VR的技术和案例,从北京到上海,都是一个字:火。

    去年大会的主发言人–Unity 大中华区boss 符国新(Allan),去年开完Unite北京大会,就立马离职创业了,选择就是VR方向,呵呵。

     

    2015年参加Unite 北京大会,启蒙了我的VR认知

     

    image

    2015.4 我首次听到关于VR、AR的演讲—原Unity亚太技术总监郭振平先生激情演讲

     

    image

    2015.4 雨松MOMO粉丝们合影; 雨松左侧妹子是其女徒弟—小七不乖(现任Unity官方社区运营官)。

     

    image

    2015.4 非常高兴的和Unity创始人David Helgason 合影留念

     

    小结:

    1. Unity开发者大会,对推动Unity技术在中国蓬勃发展功不可没,2012年Unite入华,目前已经5年了。
    2. VR技术的普及,因为Unity引擎在手游行业培养海量人才,故才得以爆发。
    3. 目前国内,VR、AR技术工作,80%的人选择的是Unity的引擎,人才基数多、迭代快。
    4. Unity 5.4 看起来不错,在画质渲染上,VR效率上,比较期待正式版发布。
    5. 相对上海精细小资,我更喜欢北京的大气浑厚:VR创业公司,北京占全国60%
    6. 拿着Android手机,出门佩戴充电宝是必须的,要不然高能量的PPT不拍照记不住。
    7. 参加开发者大会,不仅仅是听讲座,和网友见面也是必须的
    8. Unity官方今年在中国会大力推线下社区,加大走群众路线

    参考:

    去年大会博客链接: 《Unite Beijing 2015大型活动

    Unity3D for VR 学习(8): Unity Shader概述

       从西安到北京高铁上,一位VR老外团队的华人leader对VR技术做了画龙点睛:

    “3D游戏的核心部分在Render, 国内很多团队美术、程序中间缺失严重。所以3d游戏做不好。 VR这块更是至关重要。”

     

    故,欲VR,先Shader吧。

     

    1 CG规范: 计算机图形学(英语:computer graphics

    在Windows下图像渲染是DirectX; 在Linux下图形渲染是OpenGL;在苹果下新出的Metal渲染。而作为Unity3D程序,跨平台的特性则无须对这些平台一一掌握,仅需要从CG规范入手即可。

    image

     

    CGPROGRAM…ENDCG这样一个代码块中,这是一段CG程序,它会帮助程序发布Unity3D到Android、Windows、IOS时候,转换为不同渲染底层功能的。

     

    2 Unity3D Shader分类

    • 表面着色器(Surface Shader) – Unity推荐的Shader,有光照需要的必须使用surface Shader。
    • 片段着色器(Fragment Shader) – 更偏向底层一些,也比较难写。
    • 固定管线着色器(Fixed Function Shader) – 目前废弃不用,仅针对老显卡。Vr时代用不着。
      从上面看到Unity实际上在主推Standard Surface Shader,在Unity5下,提供了如下4中Shader模板。

    image

     

     

    渲染管线:从数据到最终成像的过程。

    image

     

    3 Unity3D 光照模型

    光照模型想说明的事情是当光照到一个物体表面后,视角不同看到不同的光特效,如常规的漫反射、高光、镜面反射光等。 实际上也是在模拟真实情况下人看物体的视角效果,同样的3D模型,添加不同的光照模型效果会截然不同。

    如果物体是不透明的,则物体表面呈现的颜色仅有其反射光决定,通常把反射光考虑成环境反射光(Ambient Light)漫反射光(DIffuse Light)镜面反射光(Specular Light)三个分量的组合。

     

    4 Unity3D shader Tips

    C#编码是在CPU角度;而Shader编码是在GPU角度。

    看了几天书后,发现Shader真的很酷,可以做很多CPU下编程做不到(很难)的事情。

    例如半透明、UV动画、遮挡剔除、色彩斑斓的blend等。

    • uv动画:在shader中用uv缩放、uv偏转、uv旋转。如河流流水动画、UV精灵动画。
    • 遮挡剔除:cull back\front\off. 其中VR 360就用到了《Unity3D for VR 学习(7): 360°全景照片
    • 半透明–ZTest:用在自己GameObject上
    • 半透明—ZWriter:用在遮挡物GameObject上
    • AlphaTest(DX 11不支持)  半透明的花草树木效果
    • Blender混合:如透过有颜色的玻璃,可以实现色彩斑斓的透视效果
    • Fog:全局fog、局部fog

    5 Unity3D Shader 代码片段

    SurfaceOutput结构体的定义如下

    struct SurfaceOutput {

    half3 Albedo;     //像素的颜色

    half3 Normal;     //像素的法向值

    half3 Emission;   //像素的发散颜色

    half Specular;    //像素的镜面高光

    half Gloss;       //像素的发光强度

    half Alpha;       //像素的透明度

    };

     

    表面Shader代码片段

    Shader "Custom/Diffuse Texture" {

    Properties {

    _MainTex ("Base (RGB)", 2D) = "white" {}

    }

    SubShader {

    Tags { "RenderType"="Opaque" }

    LOD 200

    CGPROGRAM

    #pragma surface surf Lambert

    sampler2D _MainTex;

    struct Input {

    float2 uv_MainTex;

    };

    void surf (Input IN, inout SurfaceOutput o) {

    half4 c = tex2D (_MainTex, IN.uv_MainTex);

    o.Albedo = c.rgb;

    o.Alpha = c.a;

    }

    ENDCG

    }

    FallBack "Diffuse"

    }

     

    CG语法,可参看《GPU 编程与CG 语言之阳春白雪下里巴人.pdf

    Unity3D for VR 学习(7): 360°全景照片

        在VR应用中,有一个相对简单的虚拟现实体验,那就是360°全景照片浏览器, 他可以使得手机拍照的”全景”照片,  得以”恢复”当时拍照的场景全貌,  这个创意的确比单纯的2d图片更有震撼力一些,故本文就制作360全景照片的过程进行简单小结。

    image

     

    Step 1:预期需求

    可以通过手机的陀螺仪,在魔镜中查看360°图片;不用依赖任何蓝牙输入,仅通过Gaze Input进行选择下一张360°图片(盯着缩放图2s,进度条旋转完成后,就切换图片;用Gear VR的磁铁触发功能也可以实现选择下一张图片)。

     

    Step 2: 准备材料

    硬件:暴风魔镜4  + 小米Note顶配版(2K屏幕)

    SDK:魔镜手柄、反畸变SDK_Unity版,或者 Google cardboard-unity,本文使用的是Googe CardBoard

     

    Step 3: 创建材质球

    360°照片,展开看就是一个投影的2D照片,这个在初中学习世界地理的时候将类似投影球形地图到2维平面上,原理类似,只不过一个360°照片的投影失真会小很多. 

    为了复原,需要建立一个3D Object\Sphere, 我们通过把图片贴到这个球体上,从内侧看效果。 然后拖放照片到Sphere上,球体放大10倍; 这个时候,发现一个问题在Game视图中看不到东西了,因为Camera没有在球心位置,修改Camera坐标为(0,0,0)位于球心。

    我们依然看不到图片,因为Spere默认用的是Unlit/Transparent Shade,他为了渲染高效,把背面给剔除了,而在这里,我们洽洽需要渲染背面,故得从新写个shade–关闭cull off。

    image

    DoubleSided.Shader文件

    Shader "Unlit/DoubleSided"
    {
        Properties
        {
            _Color("Main Color", Color) = (1,1,1,1)
            _MainTex("Texture", 2D) = "white" {}
        }
            SubShader
        {
            //Ambient pass
            Pass
            {
                Name "BASE"
                Tags {"LightMode" = "Always" /* Upgrade NOTE: changed from PixelOrNone to Always */}
                Color[_PPLAmbient]
                SetTexture[_BumpMap]
                {
                    constantColor(.5,.5,.5)
                    combine constant lerp(texture) previous
                }
            SetTexture[_MainTex]
        {
            constantColor[_Color]
            Combine texture * previous DOUBLE, texture *constant
        }

            }

            //Vertex lights
            Pass{
            Name "BASE"
            Tags {"LightMode" = "Vertex"}
            Material
        {
            Diffuse[_Color]
            Emission[_PPLAmbient]
            Shininess[_Shininess]
            Specular[_SpecColor]
        }

            SeparateSpecular On
            Lighting On
            cull off
            SetTexture[_BumpMap]
            {
                constantColor(.5,.5,.5)
                combine constant lerp(texture) previous
            }
            SetTexture[_MainTex]
            {
                Combine texture *previous DOUBLE, texture *primary
            }
        }

        }

            FallBack "Diffuse", 1
    }

     

    替换了新的Shade后,效果好了很多了,唯一有问题的是我们看到的照片是反的,故修改Spere的.Z为-10.

    image

     

    通过在Unity.Editor上Play效果,已经很不错了,至此完成了大部分的工作,下面开始”移植”到VR设备上

     

    Step 4: 添加VR Camera

    先禁用掉默认的MainCamera、light。

    然后添加VR摄像机—导入Google的CardboardSDKForUnity.unitypackage后,拖入CardboardMain.prefab到场景中。 这时候点击Play启动UnityEditor,即可看到双VR Camera的效果,点击调试快捷键:Alt + 移动鼠标,即可看到模拟的陀螺仪效果。

    这个时候打包为apk,安装到手机,用真机的陀螺仪体验,效果更酷。

     

    Step 5: 添加Gaze-and-Tap 用户界面

    完成《Step 4: 添加VR Camera》后,实际上已经完成了360°全景照片功能,但是这个仅仅是一个demo,有一个致命的痛点:只有1张照片,如果我有4张照片,每次独立打包为一个apk,这显然不合理。 故需要做一些VR交互。

    这里,我们添加4个Plane,通过上面章节的《Unity3D for VR 学习(5): VR Gaze Input》,期望可以实现通过Gaze一个Plane 3s,然后能够切换新的照片功能。

    添加Plane,坐标修改如下:

    image

    添加一个脚本,实现响应EventSystem,可通过2种办法

    方法1: 添加Event Trigger脚本,响应PointerEnter、PointerExit等方法,如图

    image

    方法2:脚本直接继承IPointerDownHandler、IPointerExitHandler等接口,这个看起来更符合程序员胃口

     

    我们通过控制Plan的Color.a来实现高亮选择,代码如下

    public void SetGazeAt(bool gazeAt)
        {
            Debug.Log("SetGazeAt: " + gazeAt);
            Renderer render = this.GetComponent<Renderer>();
            Color cor = render.material.color;
            cor.a = gazeAt ? 1f : 0.5f;
            render.material.color = cor;
        }

     

    另外,当Gaze 2s后,会动态替换material的Texture来实现替换360°照片,代码如下

    public void OnClick()
    {
        Renderer renderSrc = this.GetComponent<Renderer>();
        Renderer renderDst = pano.GetComponent<Renderer>();
        Texture tex = renderSrc.materials[0].GetTexture("_MainTex");
        renderDst.materials[0].SetTexture("_MainTex", tex);
    }

     

    备注:

    360°全景照片,非常大,有好几M,这个对手机app来说会造成文件太大,实际商用中,需要采用AB(AssetBundle)实现动态从网络侧更新360图片,那样会更酷一些(轻量级)。

     

    本文用到的完整的 demo Git地址: Git.OSChina.net

     

    昨天网上一个朋友问了一个VR问题:

    可否像3D Max那样,动态替换材质,如替换房间地板材质,实现全景照片替换?

    回答:不行,只能动态替换整个的全景照片;我昨晚细细思索,好像还是不行,除非建立3D模型,采用动态换装才能实现动态换360°照片中的大树、地板吧。

    Unity3D for VR 学习(6): 再次温故知新-3D数学

       一年前,系统学习过3D数学,并记录了一篇博客《C#程序员整理的Unity 3D笔记(十):Unity3D的位移、旋转的3D数学模型》。 一年后,再次温习之。

    坐标系:Unity3D使用左手笛卡尔坐标系(Descartes coordinate system)

    • 世界坐标系(world space):在一个游戏场景中,唯一。
    • 物体坐标系\局部坐标系(local\Object space):每个物体有各自的独立的坐标系。如桌子的物体坐标系中,扶手相对桌子腿位置。有时候,不需要对外暴漏太多细节。
    • 摄像机坐标系: 特殊的物体坐标系,用于定义物体在摄像机视野范围内,即那些物体会被摄像机绘制出来。
    • 惯性坐标系 (Intertial):一个“临时”坐标系,为了方便从世界坐标系到物体坐标系的转换,引入的新坐标系。原点和物体坐标系重合,坐标轴平行于世界坐标系。

    image

     

     

    Unity3D提供的有用的坐标系转换工具:

    1 RectTransformUtility

    Vector2 WorldToScreenPoint(Camera cam, Vector3 worldPoint)

    Ray ScreenPointToRay(Camera cam, Vector2 screenPos)

     

    2 《Unity3D项目实战笔记(1):prefab的插件方式

    下面代码可以使得:a.prefab被加载到了A的子节点下面,要使得a显示b点位置,一个办法是把a挂接到B下; 另外一个办法是用transform提供的2个方法,转换局部坐标为世界坐标,实现动态定位。

    Vector3 pos = A.transform.TransformPoint(a.localPostion);

    b.localpostion = B.transform.InverseTransformPoint(pos);

     

    向量(Vector):  有大小和方向,没有位置

    任意一点,都可以从原点开始用向量来表达,这个也是点和向量非常容易为初学者搞混的地方。同时,因为向量和位置无关,故向量可以在坐标系中任何地方使用。

    • 向量数乘,添加通过标量和向量相乘来实现力的系数调节
    • 向量标准化,大小为1的向量。亦称”法线”
    • 负向量,和原向量大小相等,方向相反的向量
    • 向量加法,向量a和向量b收尾向量,从a的尾到b的头的向量。
    • 向量减法,雷同向量加法。
    • 向量点乘(内积),结果为标量,描述了两个向量的”相似”程度,点乘结果越大,向量越接近。

    a.b >0: [0, 90), 方向相同

    a.b = 0 :90°   向量正交

    a.b<0: (90,180] 方向相反

    • 向量叉乘(叉积), 结果为一个垂直于原来的两个向量。

    矩阵(Matrix), 这里主要是2*2, 3*3, 4*4方阵

    DirectX使用的是行向量,Ope6nGL使用列向量。方阵的行可被解释为基向量

    线性变换保持直线和平行线,原点未移动;包含平移的变换称作仿射变换。

    变换物体和变换坐标系区别:变换物体,如旋转20°,意味着物体上所有的点都需要进行重新计算,被移动到新的位置。而旋转坐标系时,物体上的点实际未移动,只是在另外一个坐标系中描述他的位置而已;有时候使用变换坐标系,可以节约底层计算量。(例如碰撞检测,需要涉及的物体在同坐标系中)

    线性变换,不会导致平移(原点位置不会发生改变);放射变换在线性基础上接着进行平移。

    矩阵的行列式,结果为一个标量。

    正交矩阵,如果矩阵是正交的,则与它的转置矩阵相乘,结果为单位矩阵。同时,也可知正交矩阵的转置矩阵为逆矩阵。

    正交投影(降维操作),也称作平行投影。3D投影到2D屏幕上,该平面称作投影平面。

    透视投影,投影线不再平行而是相交于一点–投影中心。类似“小孔成像”,投影是倒着的。

    欧拉角,使用三个角度来保存方位:heading,Y轴,(-180,180);pitch, X轴, (-90, 90); bank, Z轴,(-180,180).

    四元数(Quation),用4个数字表达方位,避免了欧拉角的”万向锁”、Slerp球形差值问题。

     

    参考书籍:

    赞一下,暴风魔镜4 + 小米Note顶配2K屏,具有里程碑意义,能连续玩VR 20分钟以上

    分辨率好、陀螺仪好。

    相比之下,千元机魅蓝Note 2就是个渣渣:远离千元机,如果你玩VR的话。

    VR未来,或许能圆一个小小的遗憾:5年前曾多次出差哈尔滨,刚好有冰雪大世界,心里还是蛮想看的,但是因为畏惧寒冷(-35°的长时间户外活动),故未能出行。如果能通过VR远程看,则再好不过了,呵呵。

    Unity3D for VR 学习(5): VR Gaze Input

          在VR中,最“贴切”的输入方式是眼神,即 VR Gaze Input,如盯着某UGUI UI、某GameObject,2s后触发事件–  显示ToolTip或者切换场景等。 因为这不需要蓝牙手柄输入,显得更自然且方便,风靡VR Gear的Lamper VR游戏,就是Gaze Input(陀螺仪)的典范—可顺利完成游戏的全部过程,的确很酷。

    image

     

    UGUI UI Gaze 选择

    1 GazeInputModule(继承自PointerInputModule),挂到EventSystem实现。

    2 通过输入按钮触发选择事件;或者Gaze 2s,触发选择事件。

       这里使用了raycasting,故要求Canvas是Word坐标系,且要求有raphic Raycaster组件,并挂上Center Eye Camera(其他L、R VR Eye未测试)。

    3 EventSystem上,disable StandaloneInputModule & TouchInputModule。

    4 会触发IPointEnter事件,通过查看Button的源码知道会触发Button.Hightlight高亮

     

    GameObject Gaze 选择

    5 在上面UGUI的基础上,给Camera添加PhysicsRaycaster组件

    6 给GameObject,如Cube添加相应EventTriger:通过添加EventTrigger组件或者一个继承IPointDown**的脚本,来响应对应的Event即可。

     

    备注:在UGUI开源工程中,有很多源码值得解读

    如:ExecuteEvents.cs,核心代码片段(IEventSystemHandler):

    public static bool Execute<T>(GameObject target, BaseEventData eventData, EventFunction<T> functor) where T : IEventSystemHandler
            {
                var internalHandlers = s_HandlerListPool.Get();
                GetEventList<T>(target, internalHandlers);
                //    if (s_InternalHandlers.Count > 0)
                //        Debug.Log("Executinng " + typeof (T) + " on " + target);

                for (var i = 0; i < internalHandlers.Count; i++)
                {
                    T arg;
                    try
                    {
                        arg = (T)internalHandlers[i];
                    }
                    catch (Exception e)
                    {
                        var temp = internalHandlers[i];
                        Debug.LogException(new Exception(string.Format("Type {0} expected {1} received.", typeof(T).Name, temp.GetType().Name), e));
                        continue;
                    }

                    try
                    {
                        functor(arg, eventData);
                    }
                    catch (Exception e)
                    {
                        Debug.LogException(e);
                    }
                }

                var handlerCount = internalHandlers.Count;
                s_HandlerListPool.Release(internalHandlers);
                return handlerCount > 0;
            }

     

    如:PhysicsRaycaster.cs ,核心代码片段(Physics.RaycastAll):

    public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
            {
                if (eventCamera == null)
                    return;

                var ray = eventCamera.ScreenPointToRay(eventData.position);
                float dist = eventCamera.farClipPlane – eventCamera.nearClipPlane;

                var hits = Physics.RaycastAll(ray, dist, finalEventMask);

                if (hits.Length > 1)
                    System.Array.Sort(hits, (r1, r2) => r1.distance.CompareTo(r2.distance));

                if (hits.Length != 0)
                {
                    for (int b = 0, bmax = hits.Length; b < bmax; ++b)
                    {
                        var result = new RaycastResult
                        {
                            gameObject = hits[b].collider.gameObject,
                            module = this,
                            distance = hits[b].distance,
                            worldPosition = hits[b].point,
                            worldNormal = hits[b].normal,
                            screenPosition = eventData.position,
                            index = resultAppendList.Count,
                            sortingLayer = 0,
                            sortingOrder = 0
                        };
                        resultAppendList.Add(result);
                    }
                }
            }

     

    源码下载地址:http://pan.baidu.com/s/1hqYX2Ry 

    【按住Alt + 鼠标。 到Cube上后,2s触发“Selected”事件】

     

    参考英文:Gaze Fuse Buttons in Unity

    Unity3D for VR 学习(4): 自绘摄像机的视口区域锥体

     

         在Unity Editor下,当选择Camera组件后,可呈现出Camera视口区域锥体,非常方便。但是当选择其他物体,如Cube后,就无法得知是否在Camera市口区内了,这里我找到了雨松MOMO的一篇博客《Unity3D研究院之获取摄像机的视口区域》,他用Camera.fieldOfView和Camera.aspect算出屏幕比例,然后再得出width、height(摄像机)绘制了四边形,非常酷,可以解决这个痛点。

      我在巨人肩膀上,做了一些拓展:

    自动获得Camera的farClipPlane和nearClipPlane

    void Start()
        {
            if (!theCamera)
            {
                theCamera = this.GetComponent<Camera>();
            }

            upperDistance = theCamera.farClipPlane;
            lowerDistance = theCamera.nearClipPlane;
            tx = theCamera.transform;
        }

     

    连线far和near ClipPlane

    void FindLower2UpperCorners()
    {
        Vector3[] corners_upper = GetCorners(upperDistance);
        Vector3[] corners_lower = GetCorners(lowerDistance);

        Debug.DrawLine(corners_lower[0], corners_upper[0], Color.blue);
        Debug.DrawLine(corners_lower[1], corners_upper[1], Color.blue);
        Debug.DrawLine(corners_lower[2], corners_upper[2], Color.blue);
        Debug.DrawLine(corners_lower[3], corners_upper[3], Color.blue);
    }

     

    挂接这个CameraViewEx.cs脚本到Camera组件同GameObject即可, 运行时有效:

    image

     

    源码下载地址:http://git.oschina.net/xifarm/VR_Mojing/

     

    备注:

    不用这个脚本,直接在Game视图,打开Gizmos也可以看到Unity自带的Camera视口区域锥体。

    Unity3D for VR 学习(3): 暴风魔镜PC Input小改造–自己动手、丰衣足食

          在做手游的时候,80%时间是在PC调试的,例如业务逻辑、AI算法、核心玩法等。

    拿到魔镜提供的demo,晕了,必须得安装到Android机器上,才能调试,究其原因,有三:

    1. 需要用到手机陀螺仪
    2. 需要用到蓝牙手柄
    3. 需要用到魔镜的凸透镜

    这些都是客观原因,但是每次打包后,安装Android,再戴到头上,Debug、log啥的都看不清,呵呵。

    故就着手改造一下输入快捷键,从而可以方便的模拟手机陀螺仪输入、模拟蓝牙输入、模拟非VR Mode切换。

     

    1 模拟手机陀螺仪输入

    这个在mojing.cs有现成隐藏代码,在UpdateState()函数中。

    • 快捷键F: ok键
    • 快捷键Alt:按住,鼠标模拟GazePostion位移
    • 快捷键Ctrl:按住,鼠标模拟GazePostion旋转

    2 模拟蓝牙输入

    在学习了MojingInputManager.OnButtonDown\OnButtonUp后,知道只要传递过去string即可,其中用/分隔,第一位暂时不用,第二位用MojingKeyCode预定定义的数字。

    • 快捷键WASD:模拟蓝牙
    • 快捷键Q:模拟蓝牙OK

    3 模拟非VR Mode切换

    VR Mode切换,是通过设置Mojing.SDK.VRModeEnabled实现的,原理是对Left、Right Camera和Center Camera可见性进行隐藏或者显示实现切换,找到了Demo.cs脚本中,已经封装好了切换和返回主菜单函数,调用即可:GameObject.FindObjectOfType<Demo>().ToggleVRMode();

    • 快捷键R:模拟切换VR Mode
    • 快捷键B:模拟回到主菜单

     

    借用网络一句话:VR开发,比App开发,多一个Camera。 搭建好调试环境,就会好很多。

     

    源码下载:MojingInputManagerEditor.cs

    使用:在MojingInputManager.prefab添加MojingInputManagerEditor脚本,然后点击Apply即可。

    image