Скрипт, определяющий поведение VirtualButton - Разработка системы дополненной реальности с поддержкой распознавания жестов в режиме реального времени

/*==============================================================================Copyright (c) 2010-2013 QUALCOMM Austria Research Center GmbH. All Rights Reserved. Qualcomm Confidential and Proprietary==============================================================================*/

Using System;

Using System. Collections. Generic;

Using System. Runtime. InteropServices;

Using UnityEngine;

/// <summary>

///Этот скрипт связывает VirtualButton с виртуальным объектом

///

/// </summary>

Public class VirtualButtonBehaviour: MonoBehaviour, IEditorVirtualButtonBehaviour

{

#region PROPERTIES

/// <summary>

/// Имя виртуальной кнопки.

/// </summary>

Public string VirtualButtonName

{

Get { return mName; }

}

/// <summary>

/// Возвращает True если кнопка нажата.

/// </summary>

Public bool Pressed

{ get { return mPressed; }

}

/// <summary>

/// если позиция была обновленна

/// </summary>

Public bool HasUpdatedPose

{

Get { return mHasUpdatedPose; }

}

Public bool UnregisterOnDestroy

{

Get

{

Return mUnregisterOnDestroy;

}

Set

{

MUnregisterOnDestroy = value;

}

}

/// <summary>

/// Создание VirtualButton Object во время выполнения

/// </summary>

Public VirtualButton VirtualButton

{

Get { return mVirtualButton; }

}

#endregion // PROPERTIES

#region CONSTANTS

/// <summary>

/// Вертикальная составляющая внешнего вида кнопки

/// </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()

{

VirtualButton. RectangleData rectData = new VirtualButton. 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

}

Похожие статьи




Скрипт, определяющий поведение VirtualButton - Разработка системы дополненной реальности с поддержкой распознавания жестов в режиме реального времени

Предыдущая | Следующая