// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using UnityEngine; using UnityEngine.UI; namespace Microsoft.MixedReality.Toolkit.Input.Utilities { /// /// On Unity UI components the unity_ObjectToWorld matrix is not the transformation matrix of the local /// transform the Graphic component lives on, but that of its parent Canvas. Many MRTK/Standard shader /// effects require object scale to be known. To solve this issue the ScaleMeshEffect will store scaling /// information into UV channel attributes during UI mesh construction. Ideally we would store the scale /// in one attribute but UGUI only supports two scalers per attribute (even in the tangent attribute). /// [RequireComponent(typeof(RectTransform), typeof(Graphic))] [HelpURL("https://docs.microsoft.com/windows/mixed-reality/mrtk-unity/features/rendering/mrtk-standard-shader#ugui-support")] [AddComponentMenu("Scripts/MRTK/Services/ScaleMeshEffect")] public class ScaleMeshEffect : BaseMeshEffect { /// /// Enforces the parent canvas uses UV channel attributes. /// protected override void Awake() { base.Awake(); // Make sure the parent canvas is configured to use UV channel attributes for scaling data. var canvas = GetComponentInParent(); if (canvas != null) { canvas.additionalShaderChannels |= AdditionalCanvasShaderChannels.TexCoord2; canvas.additionalShaderChannels |= AdditionalCanvasShaderChannels.TexCoord3; } } /// /// Stores scaling information into UV channel attributes during UI mesh construction. /// /// The vertex helper to populate with new vertex data. public override void ModifyMesh(VertexHelper vh) { var rectTransform = transform as RectTransform; // Pack the 2D xy scale into UV channel 2. var scale = new Vector2(rectTransform.rect.width * rectTransform.localScale.x, rectTransform.rect.height * rectTransform.localScale.y); var canvas = GetComponentInParent(); // Pack the z scale into x and a flag indicating this value comes from a ScaleMeshEffect into y into UV channel 3. var depth = new Vector2((canvas ? (1.0f / canvas.transform.lossyScale.z) : 1.0f) * rectTransform.localScale.z, -1.0f); var vertex = new UIVertex(); for (var i = 0; i < vh.currentVertCount; ++i) { vh.PopulateUIVertex(ref vertex, i); vertex.uv2 = scale; vertex.uv3 = depth; vh.SetUIVertex(vertex, i); } } } }