0

**我正在尝试通过统一/vuforia 中的虚拟按钮显示图像。我正在创建一个可以显示的 AR 场景,但我希望使其更具交互性。

这是我需要做的:**

对于图像,将它们定义为材质的纹理并将该材质添加到场景视图中的平面网格。然后,您可以渲染平面以响应按钮事件。在 OnButtonPressed/ Released 方法中的 DefaultTrackableEventHandler 中使用代码进行渲染

这是代码,但我无法弄清楚。

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;

/// <summary>
/// This behaviour associates a Virtual Button with a game object. Use the
/// functionality in ImageTargetBehaviour to create and destroy Virtual Buttons
/// at run-time.
/// </summary>
public class VirtualButtonBehaviour : MonoBehaviour, IEditorVirtualButtonBehaviour
{

    #region PROPERTIES

    /// <summary>
    /// The names of this virtual button.
    /// </summary>
    public string VirtualButtonName
    {
        get { return mName; }
    }


    /// <summary>
    /// Returns true if this button is currently pressed.
    /// </summary>
    public bool Pressed
    {
        get { return mPressed; }
    }


    /// <summary>
    /// if the pose has been updated once
    /// </summary>
    public bool HasUpdatedPose 
    {
        get { return mHasUpdatedPose; }
    }


    /// <summary>
    /// Unregistering Virtual Buttons should only be done if they have been 
    /// registered at runtime. This property is automatically set by
    /// ImageTargetBehaviour on registration.
    /// </summary>
    public bool UnregisterOnDestroy
    {
        get
        {
            return mUnregisterOnDestroy;
        }

        set
        {
            mUnregisterOnDestroy = value;
        }
    }


    /// <summary>
    /// The VirtualButton Object created at runtime
    /// </summary>
    public VirtualButton VirtualButton
    {
        get { return mVirtualButton; }
    }

    #endregion // PROPERTIES



    #region CONSTANTS

    /// <summary>
    /// The vertical offset of the graphic representation of a virtual button in respect to the target
    /// </summary>
    public const float TARGET_OFFSET = 0.001f;

    #endregion // CONSTANTS



    #region PRIVATE_MEMBER_VARIABLES

    [SerializeField]
    [HideInInspector]
    private string mName;

    [SerializeField]
    [HideInInspector]
    private VirtualButton.Sensitivity mSensitivity;

    [SerializeField]
    [HideInInspector]
    private bool mHasUpdatedPose = false;

    [SerializeField]
    [HideInInspector]
    private Matrix4x4 mPrevTransform = Matrix4x4.zero;

    [SerializeField]
    [HideInInspector]
    private GameObject mPrevParent = null;

    private bool mSensitivityDirty;
    private bool mPreviouslyEnabled;
    private bool mPressed;
    private List<IVirtualButtonEventHandler> mHandlers = null;
    private Vector2 mLeftTop;
    private Vector2 mRightBottom;
    private bool mUnregisterOnDestroy;

    VirtualButton mVirtualButton;

    #endregion // PRIVATE_MEMBER_VARIABLES



    #region CONSTRUCTION

    public VirtualButtonBehaviour()
    {
        mName = "";
        mPressed = false;
        mSensitivity = VirtualButton.DEFAULT_SENSITIVITY;
        mSensitivityDirty = false;
        mHandlers = new List<IVirtualButtonEventHandler>();
        mHasUpdatedPose = false;
    }

    #endregion // CONSTRUCTION



    #region PUBLIC_METHODS

    /// <summary>
    /// Registers an event handler with this Virtual Button which will be called
    /// when a state changed is detected.
    /// </summary>
    public void RegisterEventHandler(IVirtualButtonEventHandler eventHandler)
    {
        mHandlers.Add(eventHandler);
    }


    /// <summary>
    /// Registers an event handler with this Virtual Button which will be called
    /// when a state changed is detected.
    /// Returns true on success. False otherwise.
    /// </summary>
    public bool UnregisterEventHandler(IVirtualButtonEventHandler eventHandler)
    {
        return mHandlers.Remove(eventHandler);
    }


    /// <summary>
    /// Calculates the 2D button area that the Virtual Button currently occupies
    /// in the Image Target.
    /// Returns true if the area was computed successfully. False otherwise.
    /// Passes out the top left and bottom right position of the rectangle area.
    /// </summary>
    public bool CalculateButtonArea(out Vector2 topLeft,
                                    out Vector2 bottomRight)
    {
        // Error if we don't have an image target as a root:
        ImageTargetBehaviour itb = this.GetImageTargetBehaviour();
        if (itb == null)
        {
            topLeft = bottomRight = Vector2.zero;
            return false;
        }

        Vector3 vbPosITSpace = itb.transform.InverseTransformPoint(
                                                this.transform.position);

        // The scale of the image Target:
        float itScale = itb.transform.lossyScale[0];

        // Scale the button position:
        Vector2 pos = new Vector2(vbPosITSpace[0] * itScale,
                                  vbPosITSpace[2] * itScale);

        // Scale the button area:
        Vector2 scale = new Vector2(this.transform.lossyScale[0],
                                    this.transform.lossyScale[2]);

        // Calculate top left and bottom right points:
        Vector2 radius = Vector2.Scale(scale * 0.5F, new Vector2(1.0f, -1.0f));

        topLeft = pos - radius;
        bottomRight = pos + radius;

        // Done:
        return true;
    }


    /// <summary>
    /// Update the virtual button rect in native
    /// </summary>
    public bool UpdateAreaRectangle()
    {
        RectangleData rectData = new RectangleData();

        rectData.leftTopX = mLeftTop.x;
        rectData.leftTopY = mLeftTop.y;
        rectData.rightBottomX = mRightBottom.x;
        rectData.rightBottomY = mRightBottom.y;

        if (mVirtualButton == null) return false;

        return mVirtualButton.SetArea(rectData);
    }


    /// <summary>
    /// Update sensitivity in native
    /// </summary>
    public bool UpdateSensitivity()
    {
        if (mVirtualButton == null) return false;

        return mVirtualButton.SetSensitivity(mSensitivity);
    }


    /// <summary>
    /// Update enabled status in native
    /// </summary>
    private bool UpdateEnabled()
    {
        return mVirtualButton.SetEnabled(enabled);
    }


    /// <summary>
    /// UpdatePose() is called each frame to ensure the virtual button is clamped
    /// to the image target plane and remains axis-aligned with respect to the
    /// target. Return true if the defining area of the virtual button has
    /// changed, false otherwise.
    /// </summary>
    public bool UpdatePose()
    {
        // The image target to which the button belongs:
        ImageTargetBehaviour itb = this.GetImageTargetBehaviour();

        // If there is no image target we return:
        if (itb == null)
        {
            return false;
        }

        // We explicitly disallow any objects with non-uniform scaling in the
        // object hierachy of the virtual button. Combined with a rotation
        // this would result in skewing the virtual button.
        Transform t = transform.parent;
        while (t != null)
        {
            if (t.localScale[0] != t.localScale[1] ||
                t.localScale[0] != t.localScale[2])
            {
                Debug.LogWarning("Detected non-uniform scale in virtual " +
                    " button object hierarchy. Forcing uniform scaling of " +
                    "object '" + t.name + "'.");

                //  Force uniform scale:
                t.localScale = new Vector3(t.localScale[0], t.localScale[0],
                                            t.localScale[0]);
            }
            t = t.parent;
        }

        // Remember we have updated once:
        mHasUpdatedPose = true;

        // Clamp to center of parent object:
        if (transform.parent != null &&
            transform.parent.gameObject != itb.gameObject)
        {
            transform.localPosition = Vector3.zero;
        }

        // Clamp position to image target plane:
        Vector3 vbPosITSpace = itb.transform.InverseTransformPoint(
                                                    this.transform.position);

        // Set the y offset in Image Target space:
        vbPosITSpace.y = TARGET_OFFSET;
        Vector3 vbPosWorldSpace = itb.transform.TransformPoint(vbPosITSpace);
        this.transform.position = vbPosWorldSpace;

        // Clamp orientation to the image target plane:
        this.transform.rotation = itb.transform.rotation;

        // Update the button area:
        Vector2 leftTop, rightBottom;
        CalculateButtonArea(out leftTop, out rightBottom);

        // Change the button area only if the change is larger than a fixed
        // proportion of the image target size:
        float threshold = itb.transform.localScale[0] * 0.001f;

        if (!Equals(leftTop, mLeftTop, threshold) ||
            !Equals(rightBottom, mRightBottom, threshold))
        {
            // Area has changed significantly:
            mLeftTop = leftTop;
            mRightBottom = rightBottom;
            return true;
        }

        // Area has not changed significantly:
        return false;
    }


    /// <summary>
    /// Called after the QCARBehaviour has updated.
    /// </summary>
    public void OnTrackerUpdated(bool pressed)
    {
        if (mPreviouslyEnabled != enabled)
        {
            mPreviouslyEnabled = enabled;
            UpdateEnabled();
        }

        if (!enabled)
        {
            return;
        }

        // Trigger the appropriate callback if there was state change:
        if (mPressed != pressed && mHandlers != null)
        {
            if (pressed)
            {
                foreach (IVirtualButtonEventHandler handler in mHandlers)
                {
                    handler.OnButtonPressed(this);
                }
            }
            else
            {
                foreach (IVirtualButtonEventHandler handler in mHandlers)
                {
                    handler.OnButtonReleased(this);
                }
            }
        }

        // Cache pressed state:
        mPressed = pressed;
    }


    /// <summary>
    /// Returns the Image Target that this Virtual Button is associated with.
    /// </summary>
    public ImageTargetBehaviour GetImageTargetBehaviour()
    {
        if (transform.parent == null)
            return null;

        GameObject p = transform.parent.gameObject;

        while (p != null)
        {
            ImageTargetBehaviour itb = p.GetComponent<ImageTargetBehaviour>();
            if (itb != null)
            {
                return itb;
            }

            if (p.transform.parent == null)
            {
                // Not found:
                return null;
            }

            p = p.transform.parent.gameObject;
        }

        // Not found:
        return null;
    }

    #endregion // PUBLIC_METHODS



    #region EDITOR_INTERFACE_IMPLEMENTATION

    // Initializes the Virtual Button name. Not allowed after runtime object has been created.
    bool IEditorVirtualButtonBehaviour.SetVirtualButtonName(string virtualButtonName)
    {
        if (mVirtualButton == null)
        {
            mName = virtualButtonName;
            return true;
        }

        return false;
    }


    VirtualButton.Sensitivity IEditorVirtualButtonBehaviour.SensitivitySetting 
    {
        get { return mSensitivity; }
    }

    // sets the sensitivity. At runtime the VirtualButton object should be used to change sensibility.
    bool IEditorVirtualButtonBehaviour.SetSensitivitySetting(VirtualButton.Sensitivity sensibility)
    {
        if (mVirtualButton == null)
        {
            mSensitivity = sensibility;
            mSensitivityDirty = true;
            return true;
        }

        return false;
    }

    Matrix4x4 IEditorVirtualButtonBehaviour.PreviousTransform
    {
        get { return mPrevTransform; } 
    }

    bool IEditorVirtualButtonBehaviour.SetPreviousTransform(Matrix4x4 transform)
    {
        if (mVirtualButton == null)
        {
            mPrevTransform = transform;
            return true;
        }

        return false;
    }

    GameObject IEditorVirtualButtonBehaviour.PreviousParent 
    {
        get { return mPrevParent; }
    }

    bool IEditorVirtualButtonBehaviour.SetPreviousParent(GameObject parent)
    {
        if (mVirtualButton == null)
        {
            mPrevParent = parent;
            return true;
        }

        return false;
    }

    // Initializes the Virtual Button runtime object
    void IEditorVirtualButtonBehaviour.InitializeVirtualButton(VirtualButton virtualButton)
    {
        mVirtualButton = virtualButton;
    }

    // Sets position and scale in the transform component of the Virtual Button
    // game object. The values are calculated from rectangle values (top-left
    // and bottom-right corners).
    // Returns false if Virtual Button is not child of an Image Target.
    bool IEditorVirtualButtonBehaviour.SetPosAndScaleFromButtonArea(Vector2 topLeft, Vector2 bottomRight)
    {
        // Error if we don't have an image target as a root:
        ImageTargetBehaviour itb = this.GetImageTargetBehaviour();
        if (itb == null)
        {
            return false;
        }

        float itScale = itb.transform.lossyScale[0];

        Vector2 pos = (topLeft + bottomRight) * 0.5f;

        Vector2 scale = new Vector2(bottomRight[0] - topLeft[0],
                                    topLeft[1] - bottomRight[1]);

        Vector3 vbPosITSpace =
            new Vector3(pos[0] / itScale, VirtualButtonBehaviour.TARGET_OFFSET,
                        pos[1] / itScale);


        Vector3 vbScaleITSpace =
            new Vector3(scale[0],
                        (scale[0] + scale[1]) * 0.5f,
                        scale[1]);

        this.transform.position = itb.transform.TransformPoint(vbPosITSpace);

        // Image Target scale is canceled out (included in both scales)
        this.transform.localScale =
            vbScaleITSpace / this.transform.parent.lossyScale[0];

        // Done:
        return true;
    }

    #endregion // EDITOR_INTERFACE_IMPLEMENTATION



    #region UNITY_MONOBEHAVIOUR_METHODS

    // Overriding standard Unity MonoBehaviour methods.

    void LateUpdate()
    {
        // Update the button pose:
        if (UpdatePose())
        {
            // Area has changed, update the QCAR trackable:
            UpdateAreaRectangle();
        }

        // Update the sensitivity of the button if it has changed since the
        // last update:
        if (mSensitivityDirty)
        {
            if (UpdateSensitivity())
            {
                mSensitivityDirty = false;
            }
        }
    }


    void OnDisable()
    {
        if (QCARRuntimeUtilities.IsQCAREnabled())
        {
            if (mPreviouslyEnabled != enabled)
            {
                mPreviouslyEnabled = enabled;
                UpdateEnabled();
            }

            // Trigger the appropriate callback if there was state change:
            if (mPressed && mHandlers != null)
            {
                foreach (IVirtualButtonEventHandler handler in mHandlers)
                {
                    handler.OnButtonReleased(this);
                }
            }

            // Cache pressed state:
            mPressed = false;
        }
    }


    void OnDestroy()
    {
        if (Application.isPlaying)
        {
            if (mUnregisterOnDestroy)
            {
                ImageTargetBehaviour itb = GetImageTargetBehaviour();
                if (itb != null)
                    itb.ImageTarget.DestroyVirtualButton(mVirtualButton);
            }
        }
    }

    #endregion // UNITY_MONOBEHAVIOUR_METHODS



    #region PRIVATE_METHODS

    private static bool Equals(Vector2 vec1, Vector2 vec2, float threshold)
    {
        Vector2 diff = vec1 - vec2;
        return (Math.Abs(diff.x) < threshold) && (Math.Abs(diff.y) < threshold);
    }

    #endregion // PRIVATE_METHODS
}
4

0 回答 0