扩展 GvrLaserPointerImpl 以获取 Google Daydream 的 Raycast 目标信息
Extending GvrLaserPointerImpl to get Raycast target info for Google Daydream
所以我正在使用以下脚本,它使用 Google 的 GvrLaserPointerImpl(Google Daydream)在我的场景中传送:
public class PlayerTeleport : MonoBehaviour {
void Update() {
if (GvrController.AppButtonUp) {
GvrLaserPointerImpl laserPointerImpl = (GvrLaserPointerImpl)GvrPointerManager.Pointer;
if (laserPointerImpl.IsPointerIntersecting) {
transform.position = new Vector3(laserPointerImpl.PointerIntersection.x, transform.position.y, laserPointerImpl.PointerIntersection.z);
}
}
}
}
对于我的游戏,我需要知道 GvrLaserPointerImpl 光线投射的目标。如果您查看 GvrLaserPointerImpl 脚本的 OnPointerEnter 参数,您可以看到有一个 targetObject 但它没有被公开暴露或以任何方式处理:
/// Implementation of GvrBasePointer for a laser pointer visual.
/// This script should be attached to the controller object.
/// The laser visual is important to help users locate their cursor
/// when its not directly in their field of view.
public class GvrLaserPointerImpl : GvrBasePointer {
/// Small offset to prevent z-fighting of the reticle (meters).
private const float Z_OFFSET_EPSILON = 0.1f;
/// Size of the reticle in meters as seen from 1 meter.
private const float RETICLE_SIZE = 0.01f;
public Camera MainCamera { private get; set; }
public Color LaserColor { private get; set; }
public LineRenderer LaserLineRenderer { get; set; }
public GameObject Reticle { get; set; }
public float MaxLaserDistance { private get; set; }
public float MaxReticleDistance { private get; set; }
// Properties exposed for testing purposes.
public Vector3 PointerIntersection { get; private set; }
public bool IsPointerIntersecting { get; private set; }
public Ray PointerIntersectionRay { get; private set; }
public override float MaxPointerDistance {
get {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
return MaxReticleDistance;
#else
return 0;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
}
public GvrLaserPointerImpl() {
MaxLaserDistance = 0.75f;
MaxReticleDistance = 2.5f;
}
#if !(UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR))
public override void OnStart() {
// Don't call base.Start() so that this pointer isn't activated when
// the editor doesn't have UNITY_HAS_GOOGLE_VR.
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
public override void OnInputModuleEnabled() {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
if (LaserLineRenderer != null) {
LaserLineRenderer.enabled = true;
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnInputModuleDisabled() {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
if (LaserLineRenderer != null) {
LaserLineRenderer.enabled = false;
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerEnter(GameObject targetObject, Vector3 intersectionPosition,
Ray intersectionRay, bool isInteractive) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
PointerIntersection = intersectionPosition;
PointerIntersectionRay = intersectionRay;
IsPointerIntersecting = true;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerHover(GameObject targetObject, Vector3 intersectionPosition,
Ray intersectionRay, bool isInteractive) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
PointerIntersection = intersectionPosition;
PointerIntersectionRay = intersectionRay;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerExit(GameObject targetObject) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
PointerIntersection = Vector3.zero;
PointerIntersectionRay = new Ray();
IsPointerIntersecting = false;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerClickDown() {
// User has performed a click on the target. In a derived class, you could
// handle visual feedback such as laser or cursor color changes here.
}
public override void OnPointerClickUp() {
// User has released a click from the target. In a derived class, you could
// handle visual feedback such as laser or cursor color changes here.
}
public override void GetPointerRadius(out float enterRadius, out float exitRadius) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
if (Reticle != null) {
float reticleScale = Reticle.transform.localScale.x;
// Fixed size for enter radius to avoid flickering.
// This will cause some slight variability based on the distance of the object
// from the camera, and is optimized for the average case.
enterRadius = RETICLE_SIZE * 0.5f;
// Dynamic size for exit radius.
// Always correct because we know the intersection point of the object and can
// therefore use the correct radius based on the object's distance from the camera.
exitRadius = reticleScale;
} else {
enterRadius = 0.0f;
exitRadius = 0.0f;
}
#else
enterRadius = 0.0f;
exitRadius = 0.0f;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
public void OnUpdate() {
// Set the reticle's position and scale
if (Reticle != null) {
if (IsPointerIntersecting) {
Vector3 difference = PointerIntersection - PointerIntersectionRay.origin;
Vector3 clampedDifference = Vector3.ClampMagnitude(difference, MaxReticleDistance);
Vector3 clampedPosition = PointerIntersectionRay.origin + clampedDifference;
Reticle.transform.position = clampedPosition;
} else {
Reticle.transform.localPosition = new Vector3(0, 0, MaxReticleDistance);
}
float reticleDistanceFromCamera =
(Reticle.transform.position - MainCamera.transform.position).magnitude;
float scale = RETICLE_SIZE * reticleDistanceFromCamera;
Reticle.transform.localScale = new Vector3(scale, scale, scale);
}
if (LaserLineRenderer == null) {
Debug.LogWarning("Line renderer is null, returning");
return;
}
// Set the line renderer positions.
Vector3 lineEndPoint;
if (IsPointerIntersecting) {
Vector3 laserDiff = PointerIntersection - base.PointerTransform.position;
float intersectionDistance = laserDiff.magnitude;
Vector3 direction = laserDiff.normalized;
float laserDistance = intersectionDistance > MaxLaserDistance ? MaxLaserDistance : intersectionDistance;
lineEndPoint = base.PointerTransform.position + (direction * laserDistance);
} else {
lineEndPoint = base.PointerTransform.position + (base.PointerTransform.forward * MaxLaserDistance);
}
LaserLineRenderer.SetPositions(new Vector3[] {base.PointerTransform.position, lineEndPoint});
// Adjust transparency
float alpha = GvrControllerVisual.AlphaValue;
LaserLineRenderer.SetColors(Color.Lerp(Color.clear, LaserColor, alpha), Color.clear);
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
我想扩展 GvrLaserPointerImpl class 并覆盖 OnPointerEnter 方法以公开公开 targetObject 这样我就可以在我的 PlayerTeleport 脚本中检查光线投射是否击中了 targetObject一个标签。我不确定在覆盖的 OnPointerEnter 方法中放入什么来访问 targetObject class。 GvrLaserPointerImpl 继承自抽象 GvrBasePointer class,因此抽象 class 中没有任何内容告诉我如何做到这一点。
如有任何帮助,我们将不胜感激!
使用 Unity 的事件系统进行交互时的典型设计模式是在实现 IEventSystemHandler 的目标对象上放置一个脚本。示例:
public class ClickResponder : MonoBehaviour, IPointerClickHandler {
public void OnPointerClick(PointerEventData eventData) {
Debug.Log("Clicked!");
}
}
如果这对您的用例不起作用,您也可以通过此 API 访问当前指向的对象:https://docs.unity3d.com/ScriptReference/EventSystems.EventSystem-currentSelectedGameObject.html
如果这些方法都不能满足您的需要,您可以像这样在 GvrLaserPointerImpl 中公开目标对象:
public GameObject TargetObject { get; private set; }
public override void OnPointerEnter(GameObject targetObject, Vector3 intersectionPosition,
Ray intersectionRay, bool isInteractive) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
TargetObject = targetObject;
PointerIntersection = intersectionPosition;
PointerIntersectionRay = intersectionRay;
IsPointerIntersecting = true;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerExit(GameObject targetObject) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
TargetObject = null;
PointerIntersection = Vector3.zero;
PointerIntersectionRay = new Ray();
IsPointerIntersecting = false;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
希望对您有所帮助!
所以我正在使用以下脚本,它使用 Google 的 GvrLaserPointerImpl(Google Daydream)在我的场景中传送:
public class PlayerTeleport : MonoBehaviour {
void Update() {
if (GvrController.AppButtonUp) {
GvrLaserPointerImpl laserPointerImpl = (GvrLaserPointerImpl)GvrPointerManager.Pointer;
if (laserPointerImpl.IsPointerIntersecting) {
transform.position = new Vector3(laserPointerImpl.PointerIntersection.x, transform.position.y, laserPointerImpl.PointerIntersection.z);
}
}
}
}
对于我的游戏,我需要知道 GvrLaserPointerImpl 光线投射的目标。如果您查看 GvrLaserPointerImpl 脚本的 OnPointerEnter 参数,您可以看到有一个 targetObject 但它没有被公开暴露或以任何方式处理:
/// Implementation of GvrBasePointer for a laser pointer visual.
/// This script should be attached to the controller object.
/// The laser visual is important to help users locate their cursor
/// when its not directly in their field of view.
public class GvrLaserPointerImpl : GvrBasePointer {
/// Small offset to prevent z-fighting of the reticle (meters).
private const float Z_OFFSET_EPSILON = 0.1f;
/// Size of the reticle in meters as seen from 1 meter.
private const float RETICLE_SIZE = 0.01f;
public Camera MainCamera { private get; set; }
public Color LaserColor { private get; set; }
public LineRenderer LaserLineRenderer { get; set; }
public GameObject Reticle { get; set; }
public float MaxLaserDistance { private get; set; }
public float MaxReticleDistance { private get; set; }
// Properties exposed for testing purposes.
public Vector3 PointerIntersection { get; private set; }
public bool IsPointerIntersecting { get; private set; }
public Ray PointerIntersectionRay { get; private set; }
public override float MaxPointerDistance {
get {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
return MaxReticleDistance;
#else
return 0;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
}
public GvrLaserPointerImpl() {
MaxLaserDistance = 0.75f;
MaxReticleDistance = 2.5f;
}
#if !(UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR))
public override void OnStart() {
// Don't call base.Start() so that this pointer isn't activated when
// the editor doesn't have UNITY_HAS_GOOGLE_VR.
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
public override void OnInputModuleEnabled() {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
if (LaserLineRenderer != null) {
LaserLineRenderer.enabled = true;
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnInputModuleDisabled() {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
if (LaserLineRenderer != null) {
LaserLineRenderer.enabled = false;
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerEnter(GameObject targetObject, Vector3 intersectionPosition,
Ray intersectionRay, bool isInteractive) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
PointerIntersection = intersectionPosition;
PointerIntersectionRay = intersectionRay;
IsPointerIntersecting = true;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerHover(GameObject targetObject, Vector3 intersectionPosition,
Ray intersectionRay, bool isInteractive) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
PointerIntersection = intersectionPosition;
PointerIntersectionRay = intersectionRay;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerExit(GameObject targetObject) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
PointerIntersection = Vector3.zero;
PointerIntersectionRay = new Ray();
IsPointerIntersecting = false;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerClickDown() {
// User has performed a click on the target. In a derived class, you could
// handle visual feedback such as laser or cursor color changes here.
}
public override void OnPointerClickUp() {
// User has released a click from the target. In a derived class, you could
// handle visual feedback such as laser or cursor color changes here.
}
public override void GetPointerRadius(out float enterRadius, out float exitRadius) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
if (Reticle != null) {
float reticleScale = Reticle.transform.localScale.x;
// Fixed size for enter radius to avoid flickering.
// This will cause some slight variability based on the distance of the object
// from the camera, and is optimized for the average case.
enterRadius = RETICLE_SIZE * 0.5f;
// Dynamic size for exit radius.
// Always correct because we know the intersection point of the object and can
// therefore use the correct radius based on the object's distance from the camera.
exitRadius = reticleScale;
} else {
enterRadius = 0.0f;
exitRadius = 0.0f;
}
#else
enterRadius = 0.0f;
exitRadius = 0.0f;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
public void OnUpdate() {
// Set the reticle's position and scale
if (Reticle != null) {
if (IsPointerIntersecting) {
Vector3 difference = PointerIntersection - PointerIntersectionRay.origin;
Vector3 clampedDifference = Vector3.ClampMagnitude(difference, MaxReticleDistance);
Vector3 clampedPosition = PointerIntersectionRay.origin + clampedDifference;
Reticle.transform.position = clampedPosition;
} else {
Reticle.transform.localPosition = new Vector3(0, 0, MaxReticleDistance);
}
float reticleDistanceFromCamera =
(Reticle.transform.position - MainCamera.transform.position).magnitude;
float scale = RETICLE_SIZE * reticleDistanceFromCamera;
Reticle.transform.localScale = new Vector3(scale, scale, scale);
}
if (LaserLineRenderer == null) {
Debug.LogWarning("Line renderer is null, returning");
return;
}
// Set the line renderer positions.
Vector3 lineEndPoint;
if (IsPointerIntersecting) {
Vector3 laserDiff = PointerIntersection - base.PointerTransform.position;
float intersectionDistance = laserDiff.magnitude;
Vector3 direction = laserDiff.normalized;
float laserDistance = intersectionDistance > MaxLaserDistance ? MaxLaserDistance : intersectionDistance;
lineEndPoint = base.PointerTransform.position + (direction * laserDistance);
} else {
lineEndPoint = base.PointerTransform.position + (base.PointerTransform.forward * MaxLaserDistance);
}
LaserLineRenderer.SetPositions(new Vector3[] {base.PointerTransform.position, lineEndPoint});
// Adjust transparency
float alpha = GvrControllerVisual.AlphaValue;
LaserLineRenderer.SetColors(Color.Lerp(Color.clear, LaserColor, alpha), Color.clear);
}
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
我想扩展 GvrLaserPointerImpl class 并覆盖 OnPointerEnter 方法以公开公开 targetObject 这样我就可以在我的 PlayerTeleport 脚本中检查光线投射是否击中了 targetObject一个标签。我不确定在覆盖的 OnPointerEnter 方法中放入什么来访问 targetObject class。 GvrLaserPointerImpl 继承自抽象 GvrBasePointer class,因此抽象 class 中没有任何内容告诉我如何做到这一点。
如有任何帮助,我们将不胜感激!
使用 Unity 的事件系统进行交互时的典型设计模式是在实现 IEventSystemHandler 的目标对象上放置一个脚本。示例:
public class ClickResponder : MonoBehaviour, IPointerClickHandler {
public void OnPointerClick(PointerEventData eventData) {
Debug.Log("Clicked!");
}
}
如果这对您的用例不起作用,您也可以通过此 API 访问当前指向的对象:https://docs.unity3d.com/ScriptReference/EventSystems.EventSystem-currentSelectedGameObject.html
如果这些方法都不能满足您的需要,您可以像这样在 GvrLaserPointerImpl 中公开目标对象:
public GameObject TargetObject { get; private set; }
public override void OnPointerEnter(GameObject targetObject, Vector3 intersectionPosition,
Ray intersectionRay, bool isInteractive) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
TargetObject = targetObject;
PointerIntersection = intersectionPosition;
PointerIntersectionRay = intersectionRay;
IsPointerIntersecting = true;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
public override void OnPointerExit(GameObject targetObject) {
#if UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
TargetObject = null;
PointerIntersection = Vector3.zero;
PointerIntersectionRay = new Ray();
IsPointerIntersecting = false;
#endif // UNITY_HAS_GOOGLEVR && (UNITY_ANDROID || UNITY_EDITOR)
}
希望对您有所帮助!