【Cloud VR】 华为SDK集成3步曲

举报
moomlu 发表于 2019/12/27 11:38:24 2019/12/27
【摘要】 Cloud VR时代,终端实现无绳化、轻便、佩戴方便,和传统VR相比,没有场地限制、成本被分担、部署成本低,将应用部署到云上可以用提升更多的算力。华为CloudVR平台提供了一套规范的接入操作,简单易行,快让你的VR应用上云吧!!!!!!

1      认知CloudVR  

VR云化后,云端可以提升逻辑计算、图像处理能力。超多核服务器、GPU集群、云的分布式计算能力均能得到很好体现,利用最新的GPU技术做渲染和人工智能做分析的能力来弥补独立VR终端的不足。

      image.png

Cloud VR时代,终端实现无绳化,轻便、佩戴方便,便于更多类型终端接入。同时,用户还可以体验到完美的多屏融合和多屏分享,网络化多人互动VR

      image.png

华为CloudVR平台将游戏和应用的渲染搬到云上,只在终端上做上传游戏操作流和播放远程渲染的游戏画面。本文旨在指导开发者将应用集成到CloudVR平台上需要如何集成华为提供的云渲染SDK

2      华为端侧SDK的开放API

2.1   HuaweiCloudRender

这个类旨在提供给开发者,如何去设置参数和远程渲染服务器做交互,上传数据流和将渲染画面从服务器下发下来。

init

初始化SDK

setConsoleLog

设置adb logcat输出级别。

setFileLog

设置日志文件路径和级别。

create

创建SDK实例。

setOnInfoListener

设置Info信息通知监听。

setreplaceStringListener

设置Error信息通知监听。

setVrSurface

设置游戏播放的画面surface

startRender

开始渲染应用。

sendHmdTracking

上报头部姿态数据。

sendControllerTracking

上报手柄姿态和按键数据。

stopRender

停止渲染应用。

destroy

销毁SDK实例。

2.2      配套Unity中的API

SDK提供的libUnityMediaSurface.so,需要在C#代码中显式导入。这个库的主要作用是设置和刷新播放器的承载画面的view,设置给播放器的view是不同于普通2D视频的,需要将View进行特殊设置。此类的主要作用是将从服务器上的视频流,刷新到播放器的View

Unity_Media_Surface_Init()

MediaSurface库初始化接

Unity_Media_Surface_SetTextureId

MediaSurface设置获取到的Unity的TextureID

Unity_Media_Surface_SetEventBase

设置事件的基数,在Init后调用,后续发送GL.IssuePluginEvent事件时以此base为基数。

Unity_Media_Surface_SetTextureParms

设置Texture的宽高,与实际的界面宽高一致。

Unity_Media_GetTextureObject

获取SurfaceTexture对象实例

Unity_Media_Surface_Update

Surface的内容进行Update操作,返回对应图像的frameIndex值,用于刷新图像和界面模型。

 

3      Android UI模块集成HuaweiCloudRender类

集成HuaweiCloudRender类,初始化SDK。此调用需要尽早,建议在application类或者主ActivityonCreate方法中调用HuaweiCloudRender.setGlobalConfig设置全局配置变量,HuaweiCloudRender.setFileLog设置日志打印路径。创建SDK实例,对HuaweiCloudRender类的实例,设置Info信息通知监听,设置Error信息通知监听。不赘述了比较直观。

private void initCloudRender() {
    HuaweiCloudRender.init(this);
    HuaweiCloudRender.setGlobalConfig("APIGW_PARA.APIGW_UPLOAD_URL", mConfig.getApigwUploadUrl());
    HuaweiCloudRender.setGlobalConfig("APP_DEMO_PARA.RENDER_SERVICE_URL", mConfig.getServiceUrl());
    HuaweiCloudRender.setFileLog(HCRLogLevel.HCR_LOG_LEVEL_DEBUG, "/sdcard/CloudVRGame/log/");
    mPlayer = HuaweiCloudRender.create();
    mPlayer.setreplaceStringListener(this);
    mPlayer.setOnInfoListener(this);
    mPlayer.authenticate(mConfig.getAppServerUrl(), "myName", "myUserID");
}

设置Error信息通知监听,当发生一些Error事件时,回调给UI界面。设置Info信息通知监听,当有Info事件发生时,回调到UI界面。Authenticate去向服务器校验是否ip地址在白名单。每次在unity里面刷新3D场景的时候,通过调用头盔和时间。mPlayer.sendHmdTracking发送头盔数据到服务端。

private void sendControllerTrackingInfo(int leftEnable, int leftBtn, float[] leftFloat, int rightEnable, int rightBtn, float[] rightFloat) {
      mPlayer.sendControllerTracking(left_Enable, left_Btn, left_Float, right_Enable, right_Btn, right_Float);
 }

mPlayer.sendControllerTracking发送手柄元数据到服务端。

private void sendHmdTrackingInfo(int frameIndex, float[] pose) {
         mPlayer.sendHmdTracking(frameIndex,pose);
         Utils.writeLog("oooo", printFloatArray1(hmd_float));
  }

4      Unity模块设置交互java模块[Z(3] 

集成SDK提供的libUnityMediaSurface.so,设置播放器view,和每帧刷新展示效果,每帧调用java模块去上传数据和拉流。如下所示。这个模块当时开发的时候也很蒙,最后找出一个合理的解释那就是,通过unity调用这个动态库生成一个异于2Dview,然后设置给播放器。每帧去刷游戏渲染的画面

1unity工程里面每帧刷新的时候调用通过AndroidJNIHelper,在untiy里面调用java代码,每次去上传手柄数据和头盔元数据到服务端[Z(4] 。见如下代码段。

private void sendCtrollerTrack(HandInfo leftHand, HandInfo rightHand)
        {
            float[] leftFloat = { leftHand.triggerValue, leftHand.touchpadAxis.x, leftHand.touchpadAxis.y, leftHand.rotation.x, leftHand.rotation.y, leftHand.rotation.z, leftHand.rotation.w, leftHand.position.x, leftHand.position.y, leftHand.position.z };
            float[] rightFloat = { rightHand.triggerValue, rightHand.touchpadAxis.x, rightHand.touchpadAxis.y, rightHand.rotation.x, rightHand.rotation.y, rightHand.rotation.z, rightHand.rotation.w, rightHand.position.x, rightHand.position.y, rightHand.position.z };
            IntPtr jLeft = AndroidJNIHelper.ConvertToJNIArray(leftFloat);
            IntPtr jRight = AndroidJNIHelper.ConvertToJNIArray(rightFloat);
            jvalue[] param = new jvalue[6];
            param[0].i = leftHand.enable ? 1 : 0;
            param[1].i = (int)leftHand.button;
            param[2].l = jLeft;
            param[3].i = rightHand.enable ? 1 : 0;
            param[4].i = (int)rightHand.button;
            param[5].l = jRight;
            if (controllerMethod == IntPtr.Zero)
            {
                controllerMethod = AndroidJNIHelper.GetMethodID(currentActivity.GetRawClass(), "sendControllerTrackingInfo");
}
 
            AndroidJNI.CallVoidMethod(currentActivity.GetRawObject(), controllerMethod, param);
        }

2、设置播放器需要展示view,然后在view里面去初始化播放器。见如下代码段。

void initUnityMediaSurface()
{
            Debug.Log("xxx vrplayer surface initUnityMediaSurface");
            Unity_Media_Surface_Init();
            eventBase = 15;
            Renderer renderer = GetComponent<Renderer>();
            if (renderer.material == null || renderer.material.mainTexture == null)
            {
                Debug.LogError("xxx vrplayer surface Can't GetNativeTextureID()");
            }
            nativeTextureID = renderer.material.mainTexture.GetNativeTextureID();  
            IssuePluginEvent(MediaSurfaceEventType.Initialize);
}

其中MediaSurface库用来初始化播放器需要的view,并且每次在view上刷新服务器传送过来的流。在UnityC#代码中导入下面函数,并且进行合理顺序设置。详细使用参考33.2 untiy库调用接口说明。

[DllImport("UnityMediaSurface")]
private static extern void Unity_Media_Surface_Init();

3、需要在C#中先获取当前Unity Activity(包含UnityPlayerActivity),即是1中集成HuaweiCloudRender类的Activity类。

需要在Activity中添加函数:void setSurfaceTexture(SurfaceTexture texture)。需要为SurfaceTexture添加onFrameAvailable回调,在回调中通知C#代码刷新TexImage。这里很重延的奥,这边是将untiy里面设置的view传给java代码去设置给播放器奥。

private void setSurfaceTexture(SurfaceTexture texture) {
        mSurfaceTexture = texture;
        mSurfaceTexture.setDefaultBufferSize(mConfig.getVideoWidth(), mConfig.getVideoHeight());
        mSurface = new Surface(mSurfaceTexture);
        mSurfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
            @Override
            public void onFrameAvailable(SurfaceTexture surfaceTexture) {
                sendMessageToUnity("UpdateTexImage", "");
                // if someTime no new frame, stop game
                sendHandlerMessage(MSG_NO_FRAME_DISPLAY, mDefaultExitGameDelayTime * 1000);
            }
        });
        sendHandlerMessage(MSG_SURFACE_READY);
}

Unity模块去设置view,然后通过java模块去调用HuaweiCloudRender和后台服务器进行交互奥。

void OnEnable()
{
    Debug.Log("kkk vrplayer surface start ");
    initUnityMediaSurface();
    currentActivity = Utils.GetActivity();
    Debug.Log("xxx Surface currentActivity:" + currentActivity);
    mSurfaceWidth = currentActivity.Call<int>("getVideoWidth");
    mSurfaceHeight = currentActivity.Call<int>("getVideoHeight");
    StartCoroutine(DelayedStartVideo());
}

如下设置view参数。

private void InitSurfaceTexture(int textureId)
        {
            Debug.Log("xxx vrplayer surface InitSurfaceTexture ");
 
            Unity_Media_Surface_SetTextureId(textureId);
            Unity_Media_Surface_SetTextureParms(mSurfaceWidth, mSurfaceHeight);  //this size should be same as the texture
            IntPtr surfaceTexture = Unity_Media_GetTextureObject();
IntPtr setTextureMethodId = AndroidJNI.GetMethodID(currentActivity.GetRawClass(), "setSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)V");           
            if ((int)setTextureMethodId == 0)
            {
                surfaceInited = false;
                return;
            }
            jvalue[] parms = new jvalue[1];
            parms[0] = new jvalue();
            parms[0].l = surfaceTexture;
            AndroidJNI.CallVoidMethod(currentActivity.GetRawObject(), setTextureMethodId, parms);
            surfaceInited = true;
        }

每帧刷新页面

public long UpdateSurface()
     {
        if (surfaceInited)
        {
            long frameIndex = Unity_Media_Surface_Update() / 1000000;
            return frameIndex;
         }
            return 0;
     }



【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。