2020-02-28 10:45:40 qq_33994566 阅读数 33
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

一个物体下有四个子物体,

  • 无论有没有子物体setactive=false,transform.childCount=4
  • 同样 即使第一个子物体隐藏,transform.GetChild(0)依然能获取到。
  • transform.GetComponentsInChildren<Transform>().Length获得的数量受子物体是否隐藏影响。隐藏就无法被找到。 注意:返回的包含父物体。

 

待更。

2016-06-16 22:16:06 Franky_Y 阅读数 3562
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

最近都在学习unity Network的知识,思绪凌乱,整理了些常用的方法和构造函数

一、添加NetworkManager组件

1、NetworkManager.StartClien():成为客户端
2、NetworkManager.StartServer():成为服务器
3、NetworkManager.StartHost():成为主机(既是服务器也是客户端)
4、ClientScene.RegisterPrefab():在客户端中注册预设体
5、NetworkManager.OnServerAddPlayer:添加玩家到服务器中,此方法也可以重载
例如:

public virtual void OnServerAddPlayer(NetworkConnection conn, short playerControllerId) {
    var player = (GameObject)GameObject.Instantiate(playerPrefab, playerSpawnPos,
          Quaternion.identity);
    NetworkServer.AddPlayerForConnection(conn, player, playerControllerId); }

6、NetworkManager.StartMatchmaker():开始Matchmaker

二、定制自己的函数

1、在服务器/主机可以调用的

// called when a client connects 
public virtual void OnServerConnect(NetworkConnection conn);

// called when a client disconnects
public virtual void OnServerDisconnect(NetworkConnection conn)
{
    NetworkServer.DestroyPlayersForConnection(conn);
}

// called when a client is ready
public virtual void OnServerReady(NetworkConnection conn)
{
    NetworkServer.SetClientReady(conn);
}

// called when a new player is added for a client
public virtual void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
    var player = (GameObject)GameObject.Instantiate(playerPrefab, playerSpawnPos,             Quaternion.identity);
    NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
}

// called when a player is removed for a client
public virtual void OnServerRemovePlayer(NetworkConnection conn, short playerControllerId)
{
    PlayerController player;
    if (conn.GetPlayer(playerControllerId, out player))
    {
        if (player.NetworkIdentity != null && player.NetworkIdentity.gameObject != null)
            NetworkServer.Destroy(player.NetworkIdentity.gameObject);
    }
}

// called when a network error occurs
public virtual void OnServerError(NetworkConnection conn, int errorCode);

2、在客户端可以调用的

// called when connected to a server
public virtual void OnClientConnect(NetworkConnection conn)
{
    ClientScene.Ready(conn);
    ClientScene.AddPlayer(0);
}

// called when disconnected from a server
public virtual void OnClientDisconnect(NetworkConnection conn)
{
    StopClient();
}

// called when a network error occurs
public virtual void OnClientError(NetworkConnection conn, int errorCode);

// called when told to be not-ready by a server
public virtual void OnClientNotReady(NetworkConnection conn);

3、在Matchmaker可以调用的

// called when a match is created
public virtual void OnMatchCreate(CreateMatchResponse matchInfo)

// called when a list of matches is received
public virtual void OnMatchList(ListMatchResponse matchList)

// called when a match is joined
public void OnMatchJoined(JoinMatchResponse matchInfo)

这些在官方文档里都有

Unity新手,仅作记录作用

2020-01-12 21:49:34 weixin_42618387 阅读数 18
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

使用步骤

文件导入,点击Manager-Create PoorConfig创建对象池,填写对象池数量(可以为多个不同物体池子)、单个对象池的名字、预设、最大容量
在这里插入图片描述
代码中获取对象

GameObject go = PoolManager.Instance.GetObject("PoolName");

隐藏对象

PoolManager.Instance.HideObjet(gameObject);

如果要在对象获取前或销毁前进行操作,预设挂载脚本继承抽象类ReuseableObject并实现两个虚方法

public abstract class ReuseableObject : MonoBehaviour
{
    public abstract void BeforeGetObject();

    public abstract void BeforeHideObject();
}

其他的有获取单个对象池所有物体、初始化所有对象池等方法,读者自己探索吧

资源地址

链接:https://pan.baidu.com/s/19dC9hISUA6GHEOzIbp1XCQ
提取码:yqjz

2017-09-04 13:46:58 su9257 阅读数 6
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

整理了下Vuforia 6-2-10 版本对应识别功能的函数


  • TrackableSettings类主要功能

    • 开启扩展追踪
    • 获取当前激活识别库名称列表
    • 激活指定的识别数据集
    • 关闭指定识别数据集
    • 动态载入识别数据集
    • 卸载所有识别数据集(识别库)
    • 设置同时识别Image的个数
    • 设置同时识别3D物体的个数

代码块如下

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Vuforia;

/// <summary>
/// 追踪功能设置类
/// </summary>
public class TrackableSettings : MonoBehaviour
{
    public const string Name = "TrackableSettings";
    static TrackableSettings() { }
    protected TrackableSettings() { }
    protected static volatile TrackableSettings instance = null;
    protected readonly object msyncRoot = new object();
    protected static readonly object mstaticSyncRoot = new object();
    public static TrackableSettings Instance
    {
        get
        {
            if (instance == null)
            {
                lock (mstaticSyncRoot)
                {
                    if (instance == null) instance = new GameObject(Name).AddComponent<TrackableSettings>();
                }
            }
            return instance;
        }
    }

    /// <summary>
    /// 识别数据集所在的文件路径
    /// </summary>
    private string dataSetDirectoryPath = null;

/// <summary>
/// 已经激活的识别数据集
/// </summary>
    protected Dictionary<string, string> mCurrentActiveDataSets = new Dictionary<string, string>();
    /// <summary>
    /// 所有数据集对应的路径
    /// </summary>
    protected Dictionary<string, string> mCurrentAllDataSets = new Dictionary<string, string>();
    /// <summary>
    /// 是否使用本地内置识别库
    /// </summary>
    public bool bLocal = false;
    /// <summary>
    /// 扩展追踪是否开启
    /// </summary>
    protected bool mExtTrackingEnabled = false;


    private void Awake()
    {
        //if (m_instance == null) m_instance = this;

        //if (gameObject.name == "GameObject") gameObject.name = Name;
    }

    private void Start()
    {
        Initialize();
    }

    private void Initialize()
    {
        dataSetDirectoryPath = Application.persistentDataPath + "/" + "DataDirectory"+"/";

        if (!Directory.Exists(dataSetDirectoryPath))
        {
            Directory.CreateDirectory(dataSetDirectoryPath);
        }
    }
    /// <summary>
    /// 获得扩展追踪开启状态
    /// </summary>
    /// <returns></returns>
    public bool IsExtendedTrackingEnabled()
    {
        return mExtTrackingEnabled;
    }

    /// <summary>
    /// 开启、关闭扩展追踪模式
    /// </summary>
    /// <param name="extTrackingEnabled">是否开启</param>
    public virtual void SwitchExtendedTracking(bool extTrackingEnabled)
    {
        //返回可以访问当前所有跟踪的状态管理器实例。
        StateManager stateManager = TrackerManager.Instance.GetStateManager();

        // 我们遍历所有trackablebehaviours启动或停止扩展跟踪他们所代表的目标。
        bool success = true;
        foreach (var tb in stateManager.GetTrackableBehaviours())
        {
            if (tb is ImageTargetBehaviour)
            {
                ImageTargetBehaviour itb = tb as ImageTargetBehaviour;
                if (extTrackingEnabled)
                {
                    if (!itb.ImageTarget.StartExtendedTracking())
                    {
                        success = false;
                        Debug.LogError("扩展跟踪开始失败,对应目标: " + itb.TrackableName);
                    }
                }
                else
                {
                    itb.ImageTarget.StopExtendedTracking();
                }
            }
            else if (tb is MultiTargetBehaviour)
            {
                MultiTargetBehaviour mtb = tb as MultiTargetBehaviour;
                if (extTrackingEnabled)
                {
                    if (!mtb.MultiTarget.StartExtendedTracking())
                    {
                        success = false;
                        Debug.LogError("Failed to start Extended Tracking on Target " + mtb.TrackableName);
                    }
                }
                else
                {
                    mtb.MultiTarget.StopExtendedTracking();
                }
            }
            else if (tb is CylinderTargetBehaviour)
            {
                CylinderTargetBehaviour ctb = tb as CylinderTargetBehaviour;
                if (extTrackingEnabled)
                {
                    if (!ctb.CylinderTarget.StartExtendedTracking())
                    {
                        success = false;
                        Debug.LogError("Failed to start Extended Tracking on Target " + ctb.TrackableName);
                    }
                }
                else
                {
                    ctb.CylinderTarget.StopExtendedTracking();
                }
            }
            else if (tb is ObjectTargetBehaviour)
            {
                ObjectTargetBehaviour otb = tb as ObjectTargetBehaviour;
                if (extTrackingEnabled)
                {
                    if (!otb.ObjectTarget.StartExtendedTracking())
                    {
                        success = false;
                        Debug.LogError("Failed to start Extended Tracking on Target " + otb.TrackableName);
                    }
                }
                else
                {
                    otb.ObjectTarget.StopExtendedTracking();
                }
            }
            else if (tb is VuMarkBehaviour)
            {
                VuMarkBehaviour vmb = tb as VuMarkBehaviour;
                if (extTrackingEnabled)
                {
                    if (!vmb.VuMarkTemplate.StartExtendedTracking())
                    {
                        success = false;
                        Debug.LogError("Failed to start Extended Tracking on Target " + vmb.TrackableName);
                    }
                }
                else
                {
                    vmb.VuMarkTemplate.StopExtendedTracking();
                }
            }
        }
        mExtTrackingEnabled = success && extTrackingEnabled;
    }
    /// <summary>
    /// 获取当前激活识别库名称列表
    /// </summary>
    /// <returns></returns>
    public List<string> GetActiveDatasetNameList()
    {
        ObjectTracker tracker = TrackerManager.Instance.GetTracker<ObjectTracker>();
        List<DataSet> activeDataSets = tracker.GetActiveDataSets().ToList();
        List<string> tempList = new List<string>();
        for (int i = 0 ; i < activeDataSets.Count ; i++)
        {
            string datasetPath = activeDataSets.ElementAt(i).Path;
            Debug.Log("datasetPath:" + datasetPath);
            string datasetName = datasetPath.Substring(datasetPath.LastIndexOf("/") + 1);
            Debug.Log("datasetName:" + datasetName);
            tempList.Add(datasetName.TrimEnd(".xml".ToCharArray()));
        }
        return tempList;
    }
    /// <summary>
    /// 激活指定的识别数据集
    /// </summary>
    /// <param name="datasetName">数据集名称或绝对路径</param>
    public virtual void ActivateDataSet(string datasetName)
    {
        if (mCurrentActiveDataSets.ContainsKey(datasetName))
        {
            Debug.Log(string.Format("要激活的识别库:{0}已经加载", datasetName));
            return;
        } 

        // objecttracker跟踪包含在数据集,提供了用于创建和方法的激活数据。
        ObjectTracker objectTracker = TrackerManager.Instance.GetTracker<ObjectTracker>();
        IEnumerable<DataSet> datasets = objectTracker.GetDataSets();

        IEnumerable<DataSet> activeDataSets = objectTracker.GetActiveDataSets();
        List<DataSet> activeDataSetsToBeRemoved = activeDataSets.ToList();

        // 1. 循环遍历所有的活动数据集并禁用它们
        foreach (DataSet ads in activeDataSetsToBeRemoved)
        {
            objectTracker.DeactivateDataSet(ads);
        }

        // 在ObjectTracker运行时,不应该对数据集进行交换
        // 2. 所以首先要关闭tracker
        objectTracker.Stop();

        // 3. 然后,查找新数据集,如果存在,激活它
        foreach (DataSet ds in datasets)
        {
            if (ds.Path.Contains(datasetName))
            {
                objectTracker.ActivateDataSet(ds);
                mCurrentActiveDataSets.Add(datasetName, ds.Path);
            }
        }

        // 4. 最后重启traker.
        objectTracker.Start();
    }

    /// <summary>
    /// 关闭指定识别数据集
    /// </summary>
    /// <param name="datasetName">数据集名称或绝对路径</param>
    public virtual void DeactivateDateset(string datasetName)
    {
        if (!mCurrentActiveDataSets.ContainsKey(datasetName))
        {
            Debug.Log(string.Format("要关闭的识别库:{0}不存在", datasetName));
            return;
        }

        ObjectTracker objectTracker = TrackerManager.Instance.GetTracker<ObjectTracker>();
        IEnumerable<DataSet> datasets = objectTracker.GetDataSets();

        IEnumerable<DataSet> activeDataSets = objectTracker.GetActiveDataSets();

        List<DataSet> activeDataSetsToBeRemoved = activeDataSets.ToList();

        List<DataSet> dataSetsToBeActive = new List<DataSet>();

        foreach (DataSet ads in activeDataSetsToBeRemoved)
        {
            if (!ads.Path.Contains(datasetName))
            {
                dataSetsToBeActive.Add(ads);
            }
            objectTracker.DeactivateDataSet(ads);
        }

        objectTracker.Stop();

        foreach (DataSet ds in dataSetsToBeActive)
        {
            objectTracker.ActivateDataSet(ds);
        }
        mCurrentActiveDataSets.Remove(datasetName);

        objectTracker.Start();
    }
    /// <summary>
    /// 载入识别数据集
    /// </summary>
    /// <param name="DataSetName">数据集名称</param>
    /// <param name="Local">是否是本地识别数据集</param>
    public virtual void LoadDataSet(string DataSetName, bool Local = true)
    {
        ObjectTracker objectTracker = TrackerManager.Instance.GetTracker<ObjectTracker>();
        objectTracker.Stop();
        bool bLoadDataSet = false;
        DataSet mDataSet = null;
        if (VuforiaRuntimeUtilities.IsVuforiaEnabled())
        {
            objectTracker = TrackerManager.Instance.GetTracker<ObjectTracker>();
            mDataSet = objectTracker.CreateDataSet();
            if (!Local)
            {
                bLoadDataSet = mDataSet.Load(dataSetDirectoryPath+DataSetName+".xml", VuforiaUnity.StorageType.STORAGE_ABSOLUTE);//绝对路径 一般用来加载网络下载的识别库(dat和xml文件)  
            }
            else
            {
                bLoadDataSet = mDataSet.Load(DataSetName);//本地预制的识别库  
            }
        }

        if (bLoadDataSet)
        {
            mCurrentAllDataSets.Add(DataSetName, mDataSet.Path);

            UpdateImageTarget();
            Debug.Log("加载识别数据库成功并激活");

            if (objectTracker.ActivateDataSet(mDataSet))
            {
                mCurrentActiveDataSets.Add(DataSetName, mDataSet.Path);
            }
            else
            {
                Debug.Log(DataSetName + "激活失败");
            }

        }
        else
        {
            Debug.Log("加载识别数据库失败");
        }

        CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_TRIGGERAUTO);

        CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO);

        objectTracker.Start();//开启识别器 (可以理解为摄像头)  
    }
    /// <summary>
    /// 更新ImageTarget上的信息
    /// </summary>
   public virtual void UpdateImageTarget()
    {
        ImageTargetBehaviour[] m_ImageTargetBehaviours = GameObject.FindObjectsOfType<ImageTargetBehaviour>();
        for (int i = 0 ; i < m_ImageTargetBehaviours.Length ; i++)
        {
            ImageTargetBehaviour imageTargetBehaviour = m_ImageTargetBehaviours[i];
            imageTargetBehaviour.name = m_ImageTargetBehaviours[i].ImageTarget.Name + "Target";
            imageTargetBehaviour.gameObject.AddComponent<DefaultTrackableEventHandler>();
            imageTargetBehaviour.gameObject.AddComponent<TurnOffBehaviour>();
        }
    }
    /// <summary>
    /// 卸载所有识别数据集(识别库)
    /// </summary>
    public virtual void UnLoadAllDataSet()
    {
        ObjectTracker objectTracker = TrackerManager.Instance.GetTracker<ObjectTracker>();
        bool isVuforiaEnabled = VuforiaRuntimeUtilities.IsVuforiaEnabled();

        if (isVuforiaEnabled)
        {
            //1. 关闭跟踪器
            objectTracker.Stop();
            //获取对应数据集合集(和激活数据集写法略有不同)
            IEnumerable<DataSet> dataSets = objectTracker.GetActiveDataSets();
            IEnumerator<DataSet> dEnumerator = dataSets.GetEnumerator();
            List<DataSet> listDataSet = new List<DataSet>();

            while (dEnumerator.MoveNext())
            {
                listDataSet.Add(dEnumerator.Current);
            }
            //关闭每一个数据集
            for (int i = 0 ; i < listDataSet.Count ; i++)
            {
                Debug.Log("关闭对应数据集:" + listDataSet[i].Path);
                objectTracker.DeactivateDataSet(listDataSet[i]);
            }

            for (int i = 0 ; i < listDataSet.Count ; i++)
            {
                Debug.Log("关闭对应数据集:" + listDataSet[i].Path);
                objectTracker.DestroyDataSet(listDataSet[i], false);
            }

            //管理所有可跟踪行为的状态
            StateManager stateManager = TrackerManager.Instance.GetStateManager();
            //ImageTargetBehaviour[] ImageTargetBehaviours = GameObject.FindObjectsOfType<ImageTargetBehaviour>();
            IEnumerable<TrackableBehaviour> IETrackableBehaviours = stateManager.GetTrackableBehaviours();
            //销毁对应创建的ImageTarget跟踪具体行为(就是在imagetarget上设置的参数)和销毁对应的GameObject
            foreach (var tb in IETrackableBehaviours)
            {
                stateManager.DestroyTrackableBehavioursForTrackable(tb.Trackable, true);
            }
            objectTracker.DestroyAllDataSets(true);
            Debug.Log("销毁识别数据成功");

            mCurrentActiveDataSets.Clear();
            mCurrentAllDataSets.Clear();
        }
        else
        {
            Debug.Log("销毁数据失败");
        }
    }

    /// <summary>
    /// 设置同时识别Image的个数
    /// </summary>
    /// <param name="TrackedCount"></param>
    public virtual void SetTrackedImageCount(int TrackedCount)
    {
        VuforiaUnity.SetHint(VuforiaUnity.VuforiaHint.HINT_MAX_SIMULTANEOUS_IMAGE_TARGETS, TrackedCount);
    }
    /// <summary>
    /// 设置同时识别3D物体的个数
    /// </summary>
    /// <param name="TrackedCount"></param>
    public virtual void SetTrackedObjectCount(int TrackedCount)
    {
        VuforiaUnity.SetHint(VuforiaUnity.VuforiaHint.HINT_MAX_SIMULTANEOUS_OBJECT_TARGETS, TrackedCount);
    }
}


  • FrameRateSettings类主要功能

    • 设置对应帧率

代码块如下:

using UnityEngine;
using Vuforia;


/// <summary>
///帧率设置类
/// </summary>
public class FrameRateSettings : MonoBehaviour
{
    public const string Name = "FrameRateSettings";
    static FrameRateSettings() { }
    protected FrameRateSettings() { }
    protected static volatile FrameRateSettings instance = null;
    protected readonly object msyncRoot = new object();
    protected static readonly object mstaticSyncRoot = new object();

    public static FrameRateSettings Instance
    {
        get
        {
            if (instance == null)
            {
                lock (mstaticSyncRoot)
                {
                    if (instance == null) instance = new GameObject(Name).AddComponent<FrameRateSettings>();
                }
            }
            return instance;
        }
    }

    void Awake()
    {
        //if (m_instance == null) m_instance = this;

        //if (gameObject.name == "GameObject") gameObject.name = Name;
    }


    void Start()
    {
        VuforiaARController.Instance.RegisterVuforiaStartedCallback(OnVuforiaStarted);
    }


    /// <summary>
    /// 高通全面启动的帧率设置回调
    /// </summary>
    private void OnVuforiaStarted()
    {
        //查询在unity中推荐的帧率(默认 AR或VR  省电 高帧数 四种模式)

        int targetFps = VuforiaRenderer.Instance.GetRecommendedFps(VuforiaRenderer.FpsHint.NONE);

        /*默认情况下,我们使用application.targetframerate设置推荐的帧速率。
         谷歌纸板不使用垂直同步,和OVR明确禁用它。如果开发商
         使用VSYNC的质量设置,他们也应该把他们的qualitysettings.vsynccount
           根据上面返回的值。
         例如:如果物体的FPS > 50 > vsynccount = 1;其他vsynccount = 2;
        */
        if (Application.targetFrameRate != targetFps)
        {
            Debug.Log("Setting frame rate to " + targetFps + "fps");
            Application.targetFrameRate = targetFps;
        }
    }

}


  • CameraSettings类主要功能

    • 开启闪光灯
    • 开启自动对焦
    • 前后摄像机切换

代码块如下:

using UnityEngine;
using System.Collections;
using Vuforia;
/// <summary>
/// 摄像机功能设置类
/// </summary>
public class CameraSettings : MonoBehaviour
{
    public const string Name = "CameraSettings";
    static CameraSettings() { }
    protected CameraSettings() { }
    protected static volatile CameraSettings instance = null;
    protected readonly object msyncRoot = new object();
    protected static readonly object mstaticSyncRoot = new object();


    public static CameraSettings Instance
    {
        get
        {
            if (instance == null)
            {
                lock (mstaticSyncRoot)
                {
                    if (instance == null) instance = new GameObject(Name).AddComponent<CameraSettings>();
                }
            }
            return instance;
        }

    }
    /// <summary>
    /// Vuforia是否完全启动
    /// </summary>
    private bool mVuforiaStarted = false;
    /// <summary>
    /// 自动对焦是否开启
    /// </summary>
    private bool mAutofocusEnabled = true;
    /// <summary>
    /// 闪光灯是否开启
    /// </summary>
    private bool mFlashTorchEnabled = false;
    /// <summary>
    /// 摄像头朝向
    /// </summary>
    private CameraDevice.CameraDirection mActiveDirection = CameraDevice.CameraDirection.CAMERA_DEFAULT;

    void Awake()
    {
        //if (m_instance == null) m_instance = this;

        //if (gameObject.name == "GameObject") gameObject.name = Name;
    }

    void Start()
    {
        VuforiaARController vuforia = VuforiaARController.Instance;
        //vuforia已经全面启动回调,包括相机和跟踪器。可以注册多个回调函数
        vuforia.RegisterVuforiaStartedCallback(OnVuforiaStarted);
        //停止和恢复的回调,这个是回复后重新让摄像机对焦(对应状态自动传入对应的bool值)
        vuforia.RegisterOnPauseCallback(OnPaused);
    }
    /// <summary>
    /// Vuforia完全启动回调
    /// </summary>
    private void OnVuforiaStarted()
    {
        mVuforiaStarted = true;
        //开启自动对焦
        SwitchAutofocus(true);
    }
    /// <summary>
    /// Vuforia停止和恢复的回调
    /// </summary>
    /// <param name="paused"></param>
    private void OnPaused(bool paused)
    {
        bool appResumed = !paused;
        if (appResumed && mVuforiaStarted)
        {
            // 恢复原来的对焦方式
            if (mAutofocusEnabled)
                CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO);
            else
                CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_NORMAL);
        }
        else
        {
            //闪光灯状态更改 因为闪光灯会自动被操作系统关闭
            mFlashTorchEnabled = false;
        }
    }

    /// <summary>
    /// 闪光灯打开或或关闭状态
    /// </summary>
    /// <returns></returns>
    public bool IsFlashTorchEnabled()
    {
        return mFlashTorchEnabled;
    }
    /// <summary>
    /// 闪光灯开关
    /// </summary>
    /// <param name="ON">是否开启闪光灯</param>
    public virtual void SwitchFlashTorch(bool ON)
    {
        if (CameraDevice.Instance.SetFlashTorchMode(ON))
        {
            Debug.Log("成功开启闪光灯 " + ON);
            mFlashTorchEnabled = ON;
        }
        else
        {
            Debug.Log("开启闪光灯失败 " + ON);
            mFlashTorchEnabled = false;
        }
    }

    public virtual bool IsAutofocusEnabled()
    {
        return mAutofocusEnabled;
    }
    /// <summary>
    /// 是否开启自动对焦
    /// </summary>
    /// <param name="ON">是否开启自动对焦</param>
    public virtual void SwitchAutofocus(bool ON)
    {
        if (ON)
        {
            if (CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO))
            {
                Debug.Log("成功开启连续对焦");
                mAutofocusEnabled = true;
            }
            else
            {
                // Fallback to normal focus mode
                Debug.Log("未能启用连续自动对焦,切换到正常对焦模式");
                mAutofocusEnabled = false;
                CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_NORMAL);
            }
        }
        else
        {
            Debug.Log("禁用连续自动对焦(启用正常对焦模式).");
            mAutofocusEnabled = false;
            CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_NORMAL);
        }
    }
    /// <summary>
    /// 强制触发一次对焦
    /// </summary>
    public virtual void TriggerAutofocusEvent()
    {

        CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_TRIGGERAUTO);

        // 恢复到原来的对焦模式
        StartCoroutine(RestoreOriginalFocusMode());
    }

    private IEnumerator RestoreOriginalFocusMode()
    {
        yield return new WaitForSeconds(1.5f);

        if (mAutofocusEnabled)
        {
            CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO);
        }
        else
        {
            CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_NORMAL);
        }
    }

    /// <summary>
    /// 前后摄像机切换
    /// </summary>
    /// <param name="camDir">摄像机方向</param>
    public virtual void SelectCamera(CameraDevice.CameraDirection camDir)
    {
        if (RestartCamera(camDir))
        {
            mActiveDirection = camDir;

            // Upon camera restart, flash is turned off
            mFlashTorchEnabled = false;
        }
    }
    /// <summary>
    /// 转换摄像机需要把原来的摄像机状态关掉卸载然后重新初始化
    /// </summary>
    /// <param name="direction">摄像机方向</param>
    /// <returns></returns>
    public virtual bool RestartCamera(CameraDevice.CameraDirection direction)
    {
        ObjectTracker tracker = TrackerManager.Instance.GetTracker<ObjectTracker>();
        if (tracker != null)
        {
            tracker.Stop();
        }

        CameraDevice.Instance.Stop();
        CameraDevice.Instance.Deinit();

        if (!CameraDevice.Instance.Init(direction))
        {
            Debug.Log("初始化失败,指定的方向为: " + direction.ToString());
            return false;
        }
        if (!CameraDevice.Instance.Start())
        {
            Debug.Log("摄像机启动失败,指定的方向为: " + direction.ToString());
            return false;
        }

        if (tracker != null)
        {
            if (!tracker.Start())
            {
                Debug.Log("Tracker重新启动失败");
                return false;
            }
        }

        return true;
    }
    /// <summary>
    /// 在IOS上翻转摄像头会出现摄像头上下颠倒的情况,在CameraDevice.Instance.Start()后调用次函数,反之忽略即可
    /// </summary>
    /// <returns></returns>
    IEnumerator Refresh()
    {
        yield return new WaitForEndOfFrame();
        Camera.main.transform.localEulerAngles = new Vector3(0, 0, 180.0f);
    }
    /// <summary>
    /// 是否为前置摄像头
    /// </summary>
    /// <returns></returns>
    public virtual bool IsFrontCameraActive()
    {
        return (mActiveDirection == CameraDevice.CameraDirection.CAMERA_FRONT);
    }

}


  • InitErrorHandler类主要功能

    • Vuforia初始化时对应错误的回调(CustomLog自己封装的)

代码块如下:

using UnityEngine;
using System.Collections;
using Vuforia;
using Custom.Log;

public class InitErrorHandler : MonoBehaviour
{
    private string key;
    void Awake()
    {
        VuforiaRuntime.Instance.RegisterVuforiaInitErrorCallback(OnInitError);
        if (Debuger.EnableLog)
        {
            Debug.Log("+");
        }
        else
        {
            Debug.Log("-");
        }
    }
    private void OnInitError(VuforiaUnity.InitError error)
    {
        if (error != VuforiaUnity.InitError.INIT_SUCCESS)
        {
            ShowErrorMessage(error);
        }
    }
    private void CustomLog(string str)
    {
        this.Log(str);
    }

    private void ShowErrorMessage(VuforiaUnity.InitError errorCode)
    {
        switch (errorCode)
        {
            //外部设备检测失败错误(摄像头)
            case VuforiaUnity.InitError.INIT_EXTERNAL_DEVICE_NOT_DETECTED:
                {
                    string temp = "Vuforia初始化失败 " + "没有设备所需的外部硬件对接";
                    CustomLog(temp);
                    break;
                }
            // 没有输入密钥的错误
            case VuforiaUnity.InitError.INIT_LICENSE_ERROR_MISSING_KEY:
                {
                    string temp = "Vuforia 密钥没有找到";
                    CustomLog(temp);
                }
                break;
            // 输入的密钥无效的错误
            case VuforiaUnity.InitError.INIT_LICENSE_ERROR_INVALID_KEY:
                {
                    key = VuforiaConfiguration.Instance.Vuforia.LicenseKey;
                    if (key.Length > 10)
                    {
                        string temp = "Vuforia 密钥无效:请申请有效的密钥";
                        CustomLog(temp);
                    }
                    else
                    {
                        string temp = "Vuforia 密钥无效:密钥不完整";
                        CustomLog(temp);
                    }
                    break;
                }
            case VuforiaUnity.InitError.INIT_LICENSE_ERROR_NO_NETWORK_TRANSIENT:
                {
                    string temp =
   "无法接触服务器。请稍后再试";
                    CustomLog(temp);
                    break;
                }
            case VuforiaUnity.InitError.INIT_LICENSE_ERROR_NO_NETWORK_PERMANENT:
                {
                    string temp =
   "没有可用的网络。请确保你与互联网连接。";
                    CustomLog(temp);
                    break;
                }
            case VuforiaUnity.InitError.INIT_LICENSE_ERROR_CANCELED_KEY:
                {
                    key = VuforiaConfiguration.Instance.Vuforia.LicenseKey;
                    string temp = "这款应用程序的许可密钥已被取消,可能不再使用";
                    CustomLog(temp);
                    break;
                }
            case VuforiaUnity.InitError.INIT_LICENSE_ERROR_PRODUCT_TYPE_MISMATCH:
                {
                    key = VuforiaConfiguration.Instance.Vuforia.LicenseKey;
                    string temp = "输入的密钥与对应的产品不相符";
                    CustomLog(temp);
                }
                break;
//#if (UNITY_IPHONE || UNITY_IOS)
                case VuforiaUnity.InitError.INIT_NO_CAMERA_ACCESS:
                {
                    string temp =
                       "当在iOS设备上运行时,用户必须明确允许该应用访问摄像头。要恢复设备上的摄像头访问权限,请访问" +
                       "Settings > Privacy > Camera > [萌伴小学堂] 然后开启权限";
                    CustomLog(temp);
                    break;
                }
//#endif
            case VuforiaUnity.InitError.INIT_DEVICE_NOT_SUPPORTED:
                {
                    string temp =
   "Vuforia初始化失败:此设备不支持";
                    CustomLog(temp);
                    break;
                }

            case VuforiaUnity.InitError.INIT_ERROR:
                {
                    string temp = "Vuforia初始化失败:未知";
                    CustomLog(temp);
                    break;
                }
        }

        Debug.Log(errorCode);



    } //PRIVATE_METHODS

}

2018-07-02 10:08:13 qq_14914623 阅读数 48
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

前言 
在使用unity3d开发实际的项目中,性能优化一直是一项不得不考虑的重点,而其中UI的优化又是绕不过去的坎,很多看似简单的UI为何会占用大量的cpu开销?本文以NGUI这套UI的解决方案为例,从源码出发,分析影响性能的原因,看清问题的本质,对症下药。

NGUI的drawcall 
在Unity中,每次引擎准备数据并通知GPU的过程称为一次Draw Call。这一过程是逐个物体进行的,对于每个物体,不只GPU的渲染,引擎重新设置Material/Shader也是一项非常耗时的操作。

说起NGUI的drawcall,UIPanel是一座绕不过的大山,看源码:

    /// <summary>
    /// List of draw calls created by this panel. Do not attempt to modify this list yourself.
    /// </summary>

    [System.NonSerialized]
    public List<UIDrawCall> drawCalls = new List<UIDrawCall>();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可以将UIDrawCall近似的理解为NGUI层对于drawcall需要用到的数据进行的一层封装,后续会写文章来分析UIDrawCall。 
这里看到UIPanel会维护一个UIDrawCall的列表,注释说明了这个列表保存的是当前panel创建的draw calls。跟踪这个列表,查询向列表添加元素的地方会发现FillAllDrawCalls 这样的一个接口:

    /// <summary>
    /// Fill the geometry fully, processing all widgets and re-creating all draw calls.
    /// </summary>

    void FillAllDrawCalls ()
    {
        for (int i = 0; i < drawCalls.Count; ++i)
            UIDrawCall.Destroy(drawCalls[i]);
        drawCalls.Clear();

        Material mat = null;
        Texture tex = null;
        Shader sdr = null;
        UIDrawCall dc = null;   // 引用类型
        int count = 0;

        if (mSortWidgets) SortWidgets();  // 对widgets进行排序

        for (int i = 0; i < widgets.Count; ++i)
        {
            UIWidget w = widgets[i];

            if (w.isVisible && w.hasVertices)
            {
                Material mt = w.material;

                if (onCreateMaterial != null) mt = onCreateMaterial(w, mt);

                Texture tx = w.mainTexture;
                Shader sd = w.shader;
                // 判断材质,贴图,shader是否与当前的widget相同,若不同则增加一个drawcall
                if (mat != mt || tex != tx || sdr != sd)
                {
                    if (dc != null && dc.verts.Count != 0)
                    {
                        drawCalls.Add(dc);
                        dc.UpdateGeometry(count);
                        dc.onRender = mOnRender;
                        mOnRender = null;
                        count = 0;
                        dc = null;
                        // 调用UpdateGeometry对Mesh,MeshRenderer,MeshFilter进行设置
                        // 之后重置dc
                    }
        ...
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

上述代码出现了另一个列表widgets:

    /// <summary>
    /// List of widgets managed by this panel. Do not attempt to modify this list yourself.
    /// </summary>

    [System.NonSerialized]
    public List<UIWidget> widgets = new List<UIWidget>();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可以看到一个UIPanel可能对应多个UIWidget,而一个UIWidget不一定会对应一个UIDrawCall(可能对应一个UIDrawCall,也可能与其他UIWidget共用一个UIDrawCall)三者间的关系可以用下图表示: 
这里写图片描述

顺藤摸瓜,可以得出函数调用栈: 
这里写图片描述

下一次,我将会着重分析SortWidgets()对于UIWidget与UIDrawCall之间关系的影响。

没有更多推荐了,返回首页