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

2016年VR的大事件: Vision VR/AR Summit 2016 大会

     正月初五,刚从老家回到西安,打开TWitter,就看到铺天盖地的 #vision summit 2016# 大会的消息。

image

我细细过了一遍,发现,这个对于2016年的VR而言,非常具有里程碑意义.

 

下面, 我摘录出几个亮点供大家参考:

#vision summit 2016#大会 由Unity公司主办,2016年2月10~11日,美国加州

image

 

参会的涵盖了国外的主要的VR、AR平台厂商。

如VR的Oculus、Sony、Steam VR、Google CardBoard。

如AR厂商Microsoft Hololens、Vuforia、Google Tango。

 

其中主要是以Unity为主游戏引擎的生态圈,融合了国际一流大厂们.

Vision summit 2016从2015年中就启动报名和运作的, 是有”预谋”的一次峰会.

image

这张曲线图,和目前国内的预测大概一致:  2016~2020年, VR会以直线速度增长; AR增长相对平缓,大约3年后的2018年才会大幅度增长–随着微软的HoloLens问世吧.

 

90%的Gear VR虚拟现实项目是基于Unity开发

image

 

Oculus VR的创始人Palmer Luckey: Gear VR中约90%的虚拟现实内容是基于Unity引擎开发的。

目前移动游戏市场的主要开发引擎为Unity,故这个结果也合情合理–人才有了,新技术才会比较好的普及。

image

 

Oculus跟Unity还宣布了一项让所有Rift用户, 都可以获得引擎Unity Pro版本四个月试用期限的合作

75美金/月 * 4月 = 300美金

实际上, Unity Person版本开发VR没有任何障碍, 故此举仅仅是市场噱头,而已.

 

Unity将支持VR场景内开发

 

image

Unreal Engine 4内容制作VR引擎,1周前的新闻,在VR圈掀起小高潮; 短短1周过后,Unity就以这个短短5分钟的视频做了回应: 我们也在搞呢.  相比低效的VR开发工作流程,在虚拟现实中开发VR能让程序员们实时了解程序运行结果,应该会极大提高工作效率。

不过,从演示看,主要是场景布局和搭建,对于写脚本为主的VR程序而已,貌似用处不大.

 

Unity原生支持Cardboard

而不再需要任何插件,这个有利于统一目前琳琅满目的CardBoard VR市场,尤其是国内,*** SDK, 均源自Google CardBoard SDK源码.  

有利于减少VR程序员的学习成本,减低VR内容制作的成本.

image

前不久的新闻,ID大神Carmack说,他要投入主要精力负责Mobile VR的位置跟踪研发。

 

Unity原生支持SteamVR

image

老板一高兴,就发硬件了: 美国电子游戏厂商Valve的CEO Gabe Newell宣布说所有参加了大会的开发者都将免费获赠一套HTC Vive Pre开发者套装 (HTC Vive Pre的价值约500美元+)

 

Oculus为Unity发布口型和声音协调同步插件

Oculus VR为虚拟现实内容制作工具Unity 5发布了一款叫Oculus OVRLipSync的插件,允许开发者将化身的嘴唇运动跟声音同步起来,让虚拟现实体验更真实自然。

杜绝假唱!

 

image

 

大会网址:http://visionsummit2016.com/

 

备注:

上面Unity宣布的一些功能,预计最快2016.3 Unity 5.4版本会部分开始支持。

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°照片中的大树、地板吧。