写一个支持SMB的手机VR播放器(二):Shader与建模

针对于上文中讲到的 Unity 端需求,首先需要验证的是拆分图像,使得左右眼显示不同内容的问题,而这就需要 Shader 的帮助。

为什么需要 Shader

CardBoard SDK 新版本接入了 UnityXR,而现代 UnityXR 采用SinglePassStereoRendering渲染,也就是所谓的单通道立体渲染。

单通道立体渲染可以提高性能,但是这也就代表摄像机 Layer 分层,一只眼看一个面片的方式行不通了。所以我们需要写一个 Shader,使得同一个物体,左右眼渲染时显示不同的贴图。

我们使用下面这张图片来验证图像裁切,该图像是 VR 视频中取出的一帧画面。

建模 与 UV

先不谈 Shader,谈谈图像展示。

经常看 VR 视频的人一眼就能看出,上面那张图片是一张左右眼图像,左眼看左边,右眼看右边,每只眼的纹理宽高比为 1:1。

细心的你可能会发现图像边缘有弧形黑边,并且画面中的桌子是弯曲的,这是因为该纹理是一个 180 度半球弧面纹理。

当然,即使是半球面,因为两只眼睛看到的画面不同,因此人眼仍旧有立体感,这与全景视频是不同的

打开 Blender,生成一个球体 Mesh:

用户在球体球心处观看内容,因此选择所有面,翻转法向,使所有面法线朝向球心:

对于上文中的视频来说,我们只需要半个球,因此删掉半个球的顶点

删掉半球后,开始调整 UV,调整前,你的 UV 应该是这样的(本博删前半球,导致左右方向相反,即图中可见颜色顺序相反):

我们需要让图像从左到右填充球面,因此分 UV 时需要让各个面紧密排列,从左到右填满 Texture,同时注意 UV 平铺的顺序应是从左到右的,如果反向则需要校正:

最后,将模型绕 x 轴旋转 -90 度,应用变换,再绕 x 轴旋转 90 度,导出 FBX 到 Unity 即可。

Shader

对于SinglePassStereoRendering 也就是单通道立体渲染来说,场景内可以获取的只有一个摄像机。

为了让左右眼看到不同的图像,我们在 Shader 中需要知道当前渲染的是左眼还是右眼。Unity 考虑到了这种情况,提供了unity_StereoEyeIndex参数标识当前渲染的眼睛。

我们的图像是横向裁切的,因此需要对 UV 的 x 进行修改:

//修改自 GoogleVR/Demos/VideoDemo StereoShader,添加了 uv.x 裁切、左右/右左判断
 v2f vert (appdata_base v) {
    v2f o;
    o.pos = GvrUnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
    o.uv.x *= 0.5f;
    if(unity_StereoEyeIndex == _IsLeftRightNormal) { // _IsLeftRightNormal: 0 右左图像 1 左右图像
        o.uv.x += 0.5f;
    }
    return o;
}

将本 Shader 指定到半球模型的材质上,并给此材质设置上面的贴图:

修改_IsLeftRightNormal的值,可以在编辑器内预览左右眼的图像(因编辑器内 unity_StereoEyeIndex 为定值 0):

编辑器内将摄像机放到球心处,可以看到正常的图像:

播放视频

播放视频原理很简单,播放插件解码,之后将插件解码出的纹理赋到指定上文 Shader 的材质中,即完成左右/右左类型的视频显示。

其他

本文仅说明了左右/右左 180 度球面类型 VR 视频的显示,上下/下上类型的 VR 视频与之类似。

接下来需要写安卓端 Java 代码解决 SMB to HTTP 的问题。

梓喵出没博客(azimiao.com)版权所有,转载请注明链接:https://www.azimiao.com/8299.html
欢迎加入梓喵出没博客交流群:313732000

我来吐槽

*

*