unity 视屏左右颠倒,解决方法

2个手机,通讯,看到的画面是左右镜像的,开始以为是前置摄像头的问题,换成后置摄像头也一样是镜像,(手机前置摄像头自拍是左右镜像,后置是正常的),换Windows 端,和手机端, Windows 本地预览是镜像,远程的显示正常,手机unity端一直是镜像,window端调用 setParameters("{\"che.video.enableRemoteViewMirror\":true}");,确实可以使远端画面反转,但UNITY并不支持。

官方说的是: “因为 Unity 的Video 是通过 SDK 的 Video raw data 渲染出来的,私有接口这些对于裸数据的设置是没有作用的。”所以如果想在 Unity显示正常的画面,通过参数设置,调用接口,就无解了,我举着求包养的牌子,但别人在手机Unity看到的是左右镜像的“养包求”那3个字,一时也看不出是什么字呀,这个问题还是的解决,不然广告不是白打了,!!:sweat::sweat:

在Windows区,看到官方建议“使用 shader 对Unity 层的 texture 直接镜像处理”,先不说 shader 我会不会先, 就 “engine.UpdateTexture(texId, uid, data, ref texWidth, ref texHeight)",得不到 texture 我就没法处理呀!

好吧,换个思路!unity 不是有摄像机吗?我把video摄下,再显示出来就行了,那么问题来了,摄像在显示,他还是镜像的,怎么办呢?那就把Camera设置成镜像就行了。

首先改写下 VideoSurface,让在UI RawImage上显示视频,在 3D物体上不好摄像,还是2D好处理,这里吐槽下声网的支持效率,因为这个问题提了一个工单,一个星期也没给出解决办法,自己摸索着强改了!!!! 以下是源码

using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.UI;
/* This example script demonstrates how to attach
 * video content to a 3D object (chenzhenyong@agora.io)
 * 
 * Agora engine outputs one local preview video and some
 * remote user video. User ID (int) is used to identify
 * these video streams. 0 is used for local preview video
 * stream, and other value stands for remote user video
 * stream.
 * 2019-04-19 修改为在 RawImage上显示 注意在RawImage上显示会上下颠倒。
 */

public class VideoSurface : MonoBehaviour
{

    private System.IntPtr data = Marshal.AllocHGlobal(1080 * 720 * 4);
    private int defWidth = 0;
    private int defHeight = 0;
    private Texture2D nativeTexture;
    agora_gaming_rtc.IRtcEngine engine;
    RawImage rend;

    void Start()
    {
        engine = agora_gaming_rtc.IRtcEngine.QueryEngine();
        if (engine == null)
            return;
        // engine.DisableVideo();
        // render video
        rend = GetComponent<RawImage>();
    }


    // Update is called once per frame
    void Update()
    {
        // process engine messages (TODO: put in some other place)
        //agora_gaming_rtc.IRtcEngine engine = agora_gaming_rtc.IRtcEngine.QueryEngine();
        if (engine == null)
            return;

        //// render video
        //Renderer rend = GetComponent<Renderer>();
        uint uid = mUid;

#if UNITY_ANDROID || UNITY_IOS || UNITY_IPHONE
        if (mEnable)
        {
            // create texture if not existent
            if (rend.texture == null)
            {
                System.IntPtr texPtr = (IntPtr)engine.GenerateNativeTexture();
                Texture2D nativeTexture = Texture2D.CreateExternalTexture(640, 360, TextureFormat.ARGB32, false, false, texPtr); // FIXME! texture size is subject to change

                rend.texture = nativeTexture;
            }
            if (rend.texture != null && rend.texture is Texture2D)
            {
                Texture2D tex = rend.texture as Texture2D;
                int texId = (int)tex.GetNativeTexturePtr();
                int texWidth = 0;
                int texHeight = 0;
                if (engine.UpdateTexture(texId, uid, data, ref texWidth, ref texHeight) == 0)
                {
                    // TODO: process texture then render
                }
            }

        }
        else
        {
            if (rend.texture != null && rend.texture is Texture2D)
            {
                Texture2D tex = rend.texture as Texture2D;
                int texId = (int)tex.GetNativeTexturePtr();
                engine.DeleteTexture(texId);
                rend.texture = null;
            }
        }

        //if (this.mAdjustTransfrom != null)
        //{
        //    Transform transform = rend.transform;
        //    this.mAdjustTransfrom(this.mUid, base.gameObject.name, ref transform);
        //}
#endif
    }

    // call this to render video stream from uid on this game object
    public void SetForUser(uint uid)
    {
        mUid = uid;
        Debug.Log("Set uid " + uid + " for " + gameObject.name);
    }

    /*
     * if enable = true, the video will render. if enable = false, the video will stop render.
     */
    public void SetEnable(bool enable)
    {
        mEnable = enable;
    }

   

    /*
     * uid = 0, it means yourself but not others, you can get others uid by Agora Engine CallBack onUserJoined.
     */
    private uint mUid = 0;

    /*
     *if disabled, then no rendering happens
     */
    private bool mEnable = true;



}

这里有个问题,改完后,显示是上下颠倒的,尴尬!!!!!!

不过没事,我们反正是要把镜像再镜像的,无所谓了

  • 新建一个 Camera,设置好大小位置,刚好视频大小就行了,对着视频Rawimage (把Rawimage放视线外面,别挡我眼睛),
  • 然后 创建一个材质Material修改名字为TargetMaterial
  • 然后创建一个Render Texture修改名字为TargetRenderTexture ,把材质TargetMaterial的Shader修改为Texture,把TargetRenderTexture拖到TargetMaterial上Shader的纹理区, 并把TargetRenderTexture拖到摄像机的TargetTexture`属性上,
  • 然后建立一个 3D物体PLANE 来显示 摄像机拍摄的内容(UI,2d物体不行,汗一个先),设置 Materials Element0TargetMaterial

这样,视频已经显示出来了,就差Camera镜像了, 新建一个脚本,附加到摄像机,注意必须选择正交相机 源码如下:

using UnityEngine;
[RequireComponent(typeof(Camera))]
[ExecuteInEditMode]
public class MirrorFlipCamera : MonoBehaviour
{
    new Camera camera;
    public bool flipHorizontal;
    void Awake()
    {
        camera = GetComponent< Camera>();
    }
    void OnPreCull()
    {
        camera.ResetWorldToCameraMatrix();
        camera.ResetProjectionMatrix();
        Vector3 scale = new Vector3(flipHorizontal ? -1 : 1, 1, 1);
        camera.projectionMatrix = camera.projectionMatrix * Matrix4x4.Scale(scale);
    }
    void OnPreRender()
    {
        GL.invertCulling = flipHorizontal;
    }

    void OnPostRender()
    {
        GL.invertCulling = false;
    }
}

设置好 flipHorizontal。OK,视频也不颠倒了,镜像也解决了,观众也可以很清楚的看到我的牌子<求包养>了。

至此,问题完美解决,致声网Unity 视频SDK遇到的坑!搞不明白为什么初始的视频流就是镜像,而不是正常的流,而要在播放端去镜像回来,这与视频内容获取有关?性能问题?底层流的东西我也搞不懂,估计声网工程师也不会理这个问题,我也没时间去等声网什么时间会出下一个版本,也不清楚会不会改进,就这样吧。望接入Unity视频直播的程序猿别再这个坑呆太久!:blush:

6赞

感谢你的分享,我们会让更多的人看到的的…:sweat_smile:

这个是unity的锅…获取的图片都会镜像颠倒的.因为unity使用左手坐标系,而大部分的算法都是以右手坐标系为计算的所以…只要经过算法处理的图像读取到unity里面都会颠倒过来