Hello,
I want to get skewed UI towards center of screen (like in Astral Chain), see example below:
Since USS doesn’t support skew property or rotation in 3D space, I’ve started searching for examples/implementation/principle of doing skew.
I’ve found this post with an example of skewing images .
Added traits for setting attributes via UXML.
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class SkewedElement : VisualElement {
private readonly Vertex[] _vertices = new Vertex[4];
private readonly ushort[] _indices = {0, 1, 2, 2, 3, 0};
public float SkewX { get; set; }
public float SkewY { get; set; }
public SkewedElement() : base() {
m_contentContainer = this;
generateVisualContent += OnGenerateVisualContent;
_vertices[0].tint = Color.white;
_vertices[1].tint = Color.white;
_vertices[2].tint = Color.white;
_vertices[3].tint = Color.white;
}
private void OnGenerateVisualContent(MeshGenerationContext mgc) {
if (contentRect.width < 0.01f || contentRect.height < 0.01f)
return;
_vertices[0].position = new Vector3(contentRect.x, contentRect.height, Vertex.nearZ);
_vertices[1].position = new Vector3(contentRect.x, contentRect.y, Vertex.nearZ);
_vertices[2].position = new Vector3(contentRect.width, contentRect.y, Vertex.nearZ);
_vertices[3].position = new Vector3(contentRect.width, contentRect.height, Vertex.nearZ);
var mwd = mgc.Allocate(_vertices.Length, _indices.Length);
var uvRegion = mwd.uvRegion;
_vertices[0].uv = new Vector2(0, 0) * uvRegion.size + uvRegion.min;
_vertices[1].uv = new Vector2(0, 1) * uvRegion.size + uvRegion.min;
_vertices[2].uv = new Vector2(1, 1) * uvRegion.size + uvRegion.min;
_vertices[3].uv = new Vector2(1, 0) * uvRegion.size + uvRegion.min;
//Skew
SkewImage(mwd.vertexCount);
mwd.SetAllVertices(_vertices);
mwd.SetAllIndices(_indices);
}
private void SkewImage(float vertexCount) {
var xskew = contentRect.height * Mathf.Tan(Mathf.Deg2Rad * SkewX);
var yskew = contentRect.width * Mathf.Tan(Mathf.Deg2Rad * SkewY);
for (int i = 0; i < vertexCount; i++) {
for (int j = 0; j < _vertices.Length; j++) {
_vertices[j].position += new Vector3(
Mathf.Lerp(0, xskew, (_vertices[j].position.y - contentRect.y) / contentRect.height),
Mathf.Lerp(0, yskew, (_vertices[j].position.x - contentRect.x) / contentRect.width));
}
}
}
VisualElement m_contentContainer;
public override VisualElement contentContainer {
get { return m_contentContainer; }
}
public new class UxmlFactory : UxmlFactory<SkewedElement, UxmlTraits> { }
public new class UxmlTraits : VisualElement.UxmlTraits {
UxmlFloatAttributeDescription m_skewX = new UxmlFloatAttributeDescription {name = "skew-x"};
UxmlFloatAttributeDescription m_skewY = new UxmlFloatAttributeDescription {name = "skew-y"};
public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription {
get { yield break; }
}
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) {
base.Init(ve, bag, cc);
SkewedElement skewedElement = ve as SkewedElement;
skewedElement.SkewX = m_skewX.GetValueFromBag(bag, cc);
skewedElement.SkewY = m_skewY.GetValueFromBag(bag, cc);
}
}
}
But it skewes element texture and doesn’t work with elements transclusion using contentContainer.
Is it even possible to use OnGenerateVisualContent to do such things, or it works only with element, where this function is overridden and ignores child elements?