Positioning and scaling the new UI in 3D world space

Hi!

I wanted to use the new UI system for player units & enemy healthbars in a 3D RTS game, but i got stuck in several aspects:

1.) Scaling: I design on the big screen and want to resize it to fit on an a small unit. When i set the scale of the panel it’s pretty unpredictable & small. As well as positioning (see below) gets even more screwed up.

2.) Positioning: I want to position it dynamically above moving gameObjects in 3D Space.

// get screen position of gameobject:
Vector3 unitPos = Camera.main.WorldToScreenPoint(transform.position);

// try to find the center by getting bounds and later dividing bounds.x by 2:
Rect r = rootPanel.worldBound; // world bounds might be wrong, but local also doesn't work
float width = r.size.x;

Vector3 v = new(unitPos.x - width/2, Screen.height - unitPos.y);
rootPanel.transform.position = v;

It almost works, but it’s not centered correctly and seems to be shifting left and right when the gameobject is moving around.

As a simple implementation, i will probably create a UI panel for each gameobject. More performant would be if I move around several VisualElements for all gameobjects on one single Panel, i guess.

Thanks, Maria!

1 Like

Ok, for 2) i found a solution here (at the end of UIToolkit + world space support status? - Unity Forum )

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class UITrackTransform : MonoBehaviour
{
    public Transform TransformToFollow;
    private VisualElement m_Bar;
    private Camera m_MainCamera;
    private void Start()
    {
        m_MainCamera = Camera.main;
        m_Bar = GetComponent<UIDocument>().rootVisualElement.Q("Container"); // your toplevel visual element goes here
        SetPosition();
    }
  
    public void SetPosition()
    {
        Vector2 newPosition = RuntimePanelUtils.CameraTransformWorldToPanel(
            m_Bar.panel, TransformToFollow.position, m_MainCamera);
        newPosition.x = (newPosition.x - m_Bar.layout.width / 2);
        m_Bar.transform.position = newPosition;
    }
  
    private void LateUpdate()
    {
        if (TransformToFollow != null)
        {
            SetPosition();
        }
    }
}
1 Like