/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * Licensed under the Oculus SDK License Agreement (the "License"); * you may not use the Oculus SDK except in compliance with the License, * which is provided at the time of installation or download, or which * otherwise accompanies this software in either electronic or hard copy form. * * You may obtain a copy of the License at * * https://developer.oculus.com/licenses/oculussdk/ * * Unless required by applicable law or agreed to in writing, the Oculus SDK * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using UnityEngine; namespace Oculus.Interaction { /// /// A collection of utility functions expanding the functionality of Unity's built-in Transform type. /// public static class TransformExtensions { /// /// Transforms a 3D position from world space to local space, ignoring scaling. /// /// /// This is useful for specialized operations which manipulate scale while performing calculations which would /// otherwise be affected by scale; for example usage, see the PanelwithManipulators sample. /// public static Vector3 InverseTransformPointUnscaled(this Transform transform, Vector3 position) { Matrix4x4 worldToLocal = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one).inverse; return worldToLocal.MultiplyPoint3x4(position); } /// /// Transforms a 3D position from local space to world space, ignoring scaling. /// /// /// This is useful for specialized operations which manipulate scale while performing calculations which would /// otherwise be affected by scale; for example usage, see the PanelwithManipulators sample. /// public static Vector3 TransformPointUnscaled(this Transform transform, Vector3 position) { Matrix4x4 localToWorld = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one); return localToWorld.MultiplyPoint3x4(position); } /// /// Transforms a bounding box from local to world space. /// /// Transfrom that is local to. /// The bounds to transform, in local space. /// The bounding box in world space. public static Bounds TransformBounds(this Transform transform, in Bounds bounds) { Bounds worldBounds = new Bounds(); Vector3 boundsMin = bounds.min; Vector3 boundsMax = bounds.max; Vector3 min = transform.position; Vector3 max = transform.position; Matrix4x4 m = transform.localToWorldMatrix; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { float e = m[i, j] * boundsMin[j]; float f = m[i, j] * boundsMax[j]; min[i] += (e < f) ? e : f; max[i] += (e < f) ? f : e; } } worldBounds.SetMinMax(min, max); return worldBounds; } /// /// Walks the hierarchy beneath searching for a Transform whose GameObject is named /// . /// /// /// This is a convience method equivalent to calling /// with a predicate that simply checks the name. /// /// The Transform which will serve as the root of the search. /// The name for which to search. /// /// The first child found with the requested name. If more than one candidate meets the requirement, there is /// no guarantee which of them will be returned. If there are no candidates, returns null. /// public static Transform FindChildRecursive(this Transform parent, string name) { return parent.FindChildRecursive((child) => child.name.Contains(name)); } /// /// Walks the hierarchy beneath searching for a Transform for which /// succeeds. /// /// The Transform which will serve as the root of the search. /// The predicate for which to search. /// /// The first child found for which the predicate succeeds. If more than one candidate meets the requirement, there is /// no guarantee which of them will be returned. If there are no candidates, returns null. /// public static Transform FindChildRecursive(this Transform parent, Predicate predicate) { foreach (Transform child in parent) { if (predicate.Invoke(child)) { return child; } Transform result = child.FindChildRecursive(predicate); if (result != null) { return result; } } return null; } } }